@theia/scm-extra 1.53.0-next.4 → 1.53.0-next.55

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.
@@ -1,197 +1,197 @@
1
- // *****************************************************************************
2
- // Copyright (C) 2018 TypeFox and others.
3
- //
4
- // This program and the accompanying materials are made available under the
5
- // terms of the Eclipse Public License v. 2.0 which is available at
6
- // http://www.eclipse.org/legal/epl-2.0.
7
- //
8
- // This Source Code may also be made available under the following Secondary
9
- // Licenses when the conditions for such availability set forth in the Eclipse
10
- // Public License v. 2.0 are satisfied: GNU General Public License, version 2
11
- // with the GNU Classpath Exception which is available at
12
- // https://www.gnu.org/software/classpath/license.html.
13
- //
14
- // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
- // *****************************************************************************
16
-
17
- import { SELECTED_CLASS, Key, Widget } from '@theia/core/lib/browser';
18
- import { ScmService } from '@theia/scm/lib/browser/scm-service';
19
- import URI from '@theia/core/lib/common/uri';
20
- import { LabelProvider } from '@theia/core/lib/browser/label-provider';
21
- import { Message } from '@theia/core/shared/@phosphor/messaging';
22
- import { ElementExt } from '@theia/core/shared/@phosphor/domutils';
23
- import { inject, injectable } from '@theia/core/shared/inversify';
24
- import { ReactWidget } from '@theia/core/lib/browser/widgets/react-widget';
25
- import * as React from '@theia/core/shared/react';
26
- import { ScmFileChangeLabelProvider } from './scm-file-change-label-provider';
27
- import { ScmFileChangeNode } from './scm-file-change-node';
28
-
29
- @injectable()
30
- export abstract class ScmNavigableListWidget<T extends { selected?: boolean }> extends ReactWidget {
31
-
32
- protected scmNodes: T[] = [];
33
- private _scrollContainer: string;
34
-
35
- @inject(ScmService) protected readonly scmService: ScmService;
36
- @inject(LabelProvider) protected readonly labelProvider: LabelProvider;
37
- @inject(ScmFileChangeLabelProvider) protected readonly scmLabelProvider: ScmFileChangeLabelProvider;
38
-
39
- constructor() {
40
- super();
41
- this.node.tabIndex = 0;
42
- }
43
-
44
- protected override onActivateRequest(msg: Message): void {
45
- super.onActivateRequest(msg);
46
- this.update();
47
- this.node.focus();
48
- }
49
-
50
- protected set scrollContainer(id: string) {
51
- this._scrollContainer = id + Date.now();
52
- }
53
-
54
- protected get scrollContainer(): string {
55
- return this._scrollContainer;
56
- }
57
-
58
- protected override onUpdateRequest(msg: Message): void {
59
- if (!this.isAttached || !this.isVisible) {
60
- return;
61
- }
62
- super.onUpdateRequest(msg);
63
- (async () => {
64
- const selected = this.node.getElementsByClassName(SELECTED_CLASS)[0];
65
- if (selected) {
66
- const container = document.getElementById(this.scrollContainer);
67
- if (container) {
68
- ElementExt.scrollIntoViewIfNeeded(container, selected);
69
- }
70
- }
71
- })();
72
- }
73
-
74
- protected override onResize(msg: Widget.ResizeMessage): void {
75
- super.onResize(msg);
76
- this.update();
77
- }
78
-
79
- protected getRepositoryLabel(uri: string): string | undefined {
80
- const repository = this.scmService.findRepository(new URI(uri));
81
- const isSelectedRepo = this.scmService.selectedRepository && repository && this.scmService.selectedRepository.provider.rootUri === repository.provider.rootUri;
82
- return repository && !isSelectedRepo ? this.labelProvider.getLongName(new URI(repository.provider.rootUri)) : undefined;
83
- }
84
-
85
- protected renderHeaderRow({ name, value, classNames, title }: { name: string, value: React.ReactNode, classNames?: string[], title?: string }): React.ReactNode {
86
- if (!value) {
87
- return;
88
- }
89
- const className = ['header-row', ...(classNames || [])].join(' ');
90
- return <div key={name} className={className} title={title}>
91
- <div className='theia-header'>{name}</div>
92
- <div className='header-value'>{value}</div>
93
- </div>;
94
- }
95
-
96
- protected addListNavigationKeyListeners(container: HTMLElement): void {
97
- this.addKeyListener(container, Key.ARROW_LEFT, () => this.navigateLeft());
98
- this.addKeyListener(container, Key.ARROW_RIGHT, () => this.navigateRight());
99
- this.addKeyListener(container, Key.ARROW_UP, () => this.navigateUp());
100
- this.addKeyListener(container, Key.ARROW_DOWN, () => this.navigateDown());
101
- this.addKeyListener(container, Key.ENTER, () => this.handleListEnter());
102
- }
103
-
104
- protected navigateLeft(): void {
105
- this.selectPreviousNode();
106
- }
107
-
108
- protected navigateRight(): void {
109
- this.selectNextNode();
110
- }
111
-
112
- protected navigateUp(): void {
113
- this.selectPreviousNode();
114
- }
115
-
116
- protected navigateDown(): void {
117
- this.selectNextNode();
118
- }
119
-
120
- protected handleListEnter(): void {
121
-
122
- }
123
-
124
- protected getSelected(): T | undefined {
125
- return this.scmNodes ? this.scmNodes.find(c => c.selected || false) : undefined;
126
- }
127
-
128
- protected selectNode(node: T): void {
129
- const n = this.getSelected();
130
- if (n) {
131
- n.selected = false;
132
- }
133
- node.selected = true;
134
- this.update();
135
- }
136
-
137
- protected selectNextNode(): void {
138
- const idx = this.indexOfSelected;
139
- if (idx >= 0 && idx < this.scmNodes.length - 1) {
140
- this.selectNode(this.scmNodes[idx + 1]);
141
- } else if (this.scmNodes.length > 0 && idx === -1) {
142
- this.selectNode(this.scmNodes[0]);
143
- }
144
- }
145
-
146
- protected selectPreviousNode(): void {
147
- const idx = this.indexOfSelected;
148
- if (idx > 0) {
149
- this.selectNode(this.scmNodes[idx - 1]);
150
- }
151
- }
152
-
153
- protected get indexOfSelected(): number {
154
- if (this.scmNodes && this.scmNodes.length > 0) {
155
- return this.scmNodes.findIndex(c => c.selected || false);
156
- }
157
- return -1;
158
- }
159
- }
160
-
161
- export namespace ScmItemComponent {
162
- export interface Props {
163
- labelProvider: LabelProvider;
164
- scmLabelProvider: ScmFileChangeLabelProvider;
165
- change: ScmFileChangeNode;
166
- revealChange: (change: ScmFileChangeNode) => void
167
- selectNode: (change: ScmFileChangeNode) => void
168
- }
169
- }
170
- export class ScmItemComponent extends React.Component<ScmItemComponent.Props> {
171
-
172
- override render(): JSX.Element {
173
- const { labelProvider, scmLabelProvider, change } = this.props;
174
- const icon = labelProvider.getIcon(change);
175
- const label = labelProvider.getName(change);
176
- const description = labelProvider.getLongName(change);
177
- const caption = scmLabelProvider.getCaption(change);
178
- const statusCaption = scmLabelProvider.getStatusCaption(change);
179
- return <div className={`scmItem noselect${change.selected ? ' ' + SELECTED_CLASS : ''}`}
180
- onDoubleClick={this.revealChange}
181
- onClick={this.selectNode}>
182
- <span className={icon + ' file-icon'}></span>
183
- <div className='noWrapInfo' title={caption} >
184
- <span className='name'>{label + ' '}</span>
185
- <span className='path'>{description}</span>
186
- </div>
187
- <div
188
- title={caption}
189
- className={change.fileChange.getClassNameForStatus()}>
190
- {statusCaption.charAt(0)}
191
- </div>
192
- </div>;
193
- }
194
-
195
- protected readonly revealChange = () => this.props.revealChange(this.props.change);
196
- protected readonly selectNode = () => this.props.selectNode(this.props.change);
197
- }
1
+ // *****************************************************************************
2
+ // Copyright (C) 2018 TypeFox and others.
3
+ //
4
+ // This program and the accompanying materials are made available under the
5
+ // terms of the Eclipse Public License v. 2.0 which is available at
6
+ // http://www.eclipse.org/legal/epl-2.0.
7
+ //
8
+ // This Source Code may also be made available under the following Secondary
9
+ // Licenses when the conditions for such availability set forth in the Eclipse
10
+ // Public License v. 2.0 are satisfied: GNU General Public License, version 2
11
+ // with the GNU Classpath Exception which is available at
12
+ // https://www.gnu.org/software/classpath/license.html.
13
+ //
14
+ // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
+ // *****************************************************************************
16
+
17
+ import { SELECTED_CLASS, Key, Widget } from '@theia/core/lib/browser';
18
+ import { ScmService } from '@theia/scm/lib/browser/scm-service';
19
+ import URI from '@theia/core/lib/common/uri';
20
+ import { LabelProvider } from '@theia/core/lib/browser/label-provider';
21
+ import { Message } from '@theia/core/shared/@phosphor/messaging';
22
+ import { ElementExt } from '@theia/core/shared/@phosphor/domutils';
23
+ import { inject, injectable } from '@theia/core/shared/inversify';
24
+ import { ReactWidget } from '@theia/core/lib/browser/widgets/react-widget';
25
+ import * as React from '@theia/core/shared/react';
26
+ import { ScmFileChangeLabelProvider } from './scm-file-change-label-provider';
27
+ import { ScmFileChangeNode } from './scm-file-change-node';
28
+
29
+ @injectable()
30
+ export abstract class ScmNavigableListWidget<T extends { selected?: boolean }> extends ReactWidget {
31
+
32
+ protected scmNodes: T[] = [];
33
+ private _scrollContainer: string;
34
+
35
+ @inject(ScmService) protected readonly scmService: ScmService;
36
+ @inject(LabelProvider) protected readonly labelProvider: LabelProvider;
37
+ @inject(ScmFileChangeLabelProvider) protected readonly scmLabelProvider: ScmFileChangeLabelProvider;
38
+
39
+ constructor() {
40
+ super();
41
+ this.node.tabIndex = 0;
42
+ }
43
+
44
+ protected override onActivateRequest(msg: Message): void {
45
+ super.onActivateRequest(msg);
46
+ this.update();
47
+ this.node.focus();
48
+ }
49
+
50
+ protected set scrollContainer(id: string) {
51
+ this._scrollContainer = id + Date.now();
52
+ }
53
+
54
+ protected get scrollContainer(): string {
55
+ return this._scrollContainer;
56
+ }
57
+
58
+ protected override onUpdateRequest(msg: Message): void {
59
+ if (!this.isAttached || !this.isVisible) {
60
+ return;
61
+ }
62
+ super.onUpdateRequest(msg);
63
+ (async () => {
64
+ const selected = this.node.getElementsByClassName(SELECTED_CLASS)[0];
65
+ if (selected) {
66
+ const container = document.getElementById(this.scrollContainer);
67
+ if (container) {
68
+ ElementExt.scrollIntoViewIfNeeded(container, selected);
69
+ }
70
+ }
71
+ })();
72
+ }
73
+
74
+ protected override onResize(msg: Widget.ResizeMessage): void {
75
+ super.onResize(msg);
76
+ this.update();
77
+ }
78
+
79
+ protected getRepositoryLabel(uri: string): string | undefined {
80
+ const repository = this.scmService.findRepository(new URI(uri));
81
+ const isSelectedRepo = this.scmService.selectedRepository && repository && this.scmService.selectedRepository.provider.rootUri === repository.provider.rootUri;
82
+ return repository && !isSelectedRepo ? this.labelProvider.getLongName(new URI(repository.provider.rootUri)) : undefined;
83
+ }
84
+
85
+ protected renderHeaderRow({ name, value, classNames, title }: { name: string, value: React.ReactNode, classNames?: string[], title?: string }): React.ReactNode {
86
+ if (!value) {
87
+ return;
88
+ }
89
+ const className = ['header-row', ...(classNames || [])].join(' ');
90
+ return <div key={name} className={className} title={title}>
91
+ <div className='theia-header'>{name}</div>
92
+ <div className='header-value'>{value}</div>
93
+ </div>;
94
+ }
95
+
96
+ protected addListNavigationKeyListeners(container: HTMLElement): void {
97
+ this.addKeyListener(container, Key.ARROW_LEFT, () => this.navigateLeft());
98
+ this.addKeyListener(container, Key.ARROW_RIGHT, () => this.navigateRight());
99
+ this.addKeyListener(container, Key.ARROW_UP, () => this.navigateUp());
100
+ this.addKeyListener(container, Key.ARROW_DOWN, () => this.navigateDown());
101
+ this.addKeyListener(container, Key.ENTER, () => this.handleListEnter());
102
+ }
103
+
104
+ protected navigateLeft(): void {
105
+ this.selectPreviousNode();
106
+ }
107
+
108
+ protected navigateRight(): void {
109
+ this.selectNextNode();
110
+ }
111
+
112
+ protected navigateUp(): void {
113
+ this.selectPreviousNode();
114
+ }
115
+
116
+ protected navigateDown(): void {
117
+ this.selectNextNode();
118
+ }
119
+
120
+ protected handleListEnter(): void {
121
+
122
+ }
123
+
124
+ protected getSelected(): T | undefined {
125
+ return this.scmNodes ? this.scmNodes.find(c => c.selected || false) : undefined;
126
+ }
127
+
128
+ protected selectNode(node: T): void {
129
+ const n = this.getSelected();
130
+ if (n) {
131
+ n.selected = false;
132
+ }
133
+ node.selected = true;
134
+ this.update();
135
+ }
136
+
137
+ protected selectNextNode(): void {
138
+ const idx = this.indexOfSelected;
139
+ if (idx >= 0 && idx < this.scmNodes.length - 1) {
140
+ this.selectNode(this.scmNodes[idx + 1]);
141
+ } else if (this.scmNodes.length > 0 && idx === -1) {
142
+ this.selectNode(this.scmNodes[0]);
143
+ }
144
+ }
145
+
146
+ protected selectPreviousNode(): void {
147
+ const idx = this.indexOfSelected;
148
+ if (idx > 0) {
149
+ this.selectNode(this.scmNodes[idx - 1]);
150
+ }
151
+ }
152
+
153
+ protected get indexOfSelected(): number {
154
+ if (this.scmNodes && this.scmNodes.length > 0) {
155
+ return this.scmNodes.findIndex(c => c.selected || false);
156
+ }
157
+ return -1;
158
+ }
159
+ }
160
+
161
+ export namespace ScmItemComponent {
162
+ export interface Props {
163
+ labelProvider: LabelProvider;
164
+ scmLabelProvider: ScmFileChangeLabelProvider;
165
+ change: ScmFileChangeNode;
166
+ revealChange: (change: ScmFileChangeNode) => void
167
+ selectNode: (change: ScmFileChangeNode) => void
168
+ }
169
+ }
170
+ export class ScmItemComponent extends React.Component<ScmItemComponent.Props> {
171
+
172
+ override render(): JSX.Element {
173
+ const { labelProvider, scmLabelProvider, change } = this.props;
174
+ const icon = labelProvider.getIcon(change);
175
+ const label = labelProvider.getName(change);
176
+ const description = labelProvider.getLongName(change);
177
+ const caption = scmLabelProvider.getCaption(change);
178
+ const statusCaption = scmLabelProvider.getStatusCaption(change);
179
+ return <div className={`scmItem noselect${change.selected ? ' ' + SELECTED_CLASS : ''}`}
180
+ onDoubleClick={this.revealChange}
181
+ onClick={this.selectNode}>
182
+ <span className={icon + ' file-icon'}></span>
183
+ <div className='noWrapInfo' title={caption} >
184
+ <span className='name'>{label + ' '}</span>
185
+ <span className='path'>{description}</span>
186
+ </div>
187
+ <div
188
+ title={caption}
189
+ className={change.fileChange.getClassNameForStatus()}>
190
+ {statusCaption.charAt(0)}
191
+ </div>
192
+ </div>;
193
+ }
194
+
195
+ protected readonly revealChange = () => this.props.revealChange(this.props.change);
196
+ protected readonly selectNode = () => this.props.selectNode(this.props.change);
197
+ }