11import { AccordionUiExtension } from "../accordionUiExtension" ;
22import { UiElementFactory } from "../utils/UiElementFactory" ;
3- import { LabelType } from "./LabelType" ;
3+ import { LabelAssignment , LabelType } from "./LabelType" ;
44import { inject } from "inversify" ;
55import { LabelTypeRegistry } from "./LabelTypeRegistry" ;
66
7- import ' ./labelTypeEditorUi.css'
7+ import " ./labelTypeEditorUi.css" ;
88import { dynamicallySetInputSize } from "../utils/TextSize" ;
9+ import { LABEL_ASSIGNMENT_MIME_TYPE } from "./dragAndDrop" ;
10+ import { AddLabelAssignmentAction } from "./command" ;
11+ import { IActionDispatcher , TYPES } from "sprotty" ;
912
1013export class LabelTypeEditorUi extends AccordionUiExtension {
1114 static readonly ID = "label-type-editor-ui" ;
12- private labelSectionContainer ?: HTMLElement
15+ private labelSectionContainer ?: HTMLElement ;
1316
14- constructor ( @inject ( LabelTypeRegistry ) private labelTypeRegistry : LabelTypeRegistry ) {
15- super ( ' left' , ' down' )
16- labelTypeRegistry . onUpdate ( ( ) => this . renderLabelTypes ( ) )
17+ constructor ( @inject ( LabelTypeRegistry ) private labelTypeRegistry : LabelTypeRegistry , @ inject ( TYPES . IActionDispatcher ) private readonly actionDispatcher : IActionDispatcher ) {
18+ super ( " left" , " down" ) ;
19+ labelTypeRegistry . onUpdate ( ( ) => this . renderLabelTypes ( ) ) ;
1720 }
18-
21+
1922 id ( ) : string {
20- return LabelTypeEditorUi . ID
23+ return LabelTypeEditorUi . ID ;
2124 }
2225 containerClass ( ) : string {
23- return LabelTypeEditorUi . ID
26+ return LabelTypeEditorUi . ID ;
2427 }
2528
2629 protected initializeHidableContent ( contentElement : HTMLElement ) {
27- const addButton = UiElementFactory . buildAddButton ( ' Label Type' )
30+ const addButton = UiElementFactory . buildAddButton ( " Label Type" ) ;
2831
2932 addButton . onclick = ( ) => {
30- this . labelTypeRegistry . registerLabelType ( '' )
31- }
33+ this . labelTypeRegistry . registerLabelType ( "" ) ;
34+ } ;
3235
33- this . labelSectionContainer = document . createElement ( ' div' )
34- this . renderLabelTypes ( )
36+ this . labelSectionContainer = document . createElement ( " div" ) ;
37+ this . renderLabelTypes ( ) ;
3538
36- contentElement . appendChild ( this . labelSectionContainer )
37- contentElement . appendChild ( addButton )
39+ contentElement . appendChild ( this . labelSectionContainer ) ;
40+ contentElement . appendChild ( addButton ) ;
3841 }
3942 protected initializeHeaderContent ( headerElement : HTMLElement ) {
40- headerElement . innerText = ' Label Types'
43+ headerElement . innerText = " Label Types" ;
4144 }
4245
4346 private renderLabelTypes ( ) : void {
4447 if ( ! this . labelSectionContainer ) {
45- return
48+ return ;
4649 }
47- this . labelSectionContainer . innerHTML = '' ;
48- const labelTypes = this . labelTypeRegistry . getLabelTypes ( )
50+ this . labelSectionContainer . innerHTML = "" ;
51+ const labelTypes = this . labelTypeRegistry . getLabelTypes ( ) ;
4952 for ( let i = 0 ; i < labelTypes . length ; i ++ ) {
50- this . labelSectionContainer . appendChild ( this . buildLabelTypeSection ( labelTypes [ i ] ) )
53+ this . labelSectionContainer . appendChild ( this . buildLabelTypeSection ( labelTypes [ i ] ) ) ;
5154 if ( i < labelTypes . length - 1 ) {
52- this . labelSectionContainer . appendChild ( document . createElement ( 'hr' ) )
55+ this . labelSectionContainer . appendChild ( document . createElement ( "hr" ) ) ;
5356 }
5457 }
5558 }
5659
5760 private buildLabelTypeSection ( labelType : LabelType ) : HTMLElement {
58- const section = document . createElement ( ' div' )
59- section . classList . add ( ' label-section' )
60-
61- const nameInput = document . createElement ( ' input' )
62- nameInput . classList . add ( ' label-type-name' )
63- const deleteButton = UiElementFactory . buildDeleteButton ( )
64- const labelTypeValueHolder = document . createElement ( ' div' )
65- labelTypeValueHolder . classList . add ( ' label-type-values' )
66- const addButton = UiElementFactory . buildAddButton ( ' Value' )
67- addButton . classList . add ( ' label-type-value-add' )
68-
69- nameInput . value = labelType . name
70- nameInput . placeholder = ' Label Type Name'
71- nameInput . oninput = ( e : InputEvent ) => this . onInputHandler ( e , nameInput )
72- setTimeout ( ( ) => dynamicallySetInputSize ( nameInput ) , 0 )
61+ const section = document . createElement ( " div" ) ;
62+ section . classList . add ( " label-section" ) ;
63+
64+ const nameInput = document . createElement ( " input" ) ;
65+ nameInput . classList . add ( " label-type-name" ) ;
66+ const deleteButton = UiElementFactory . buildDeleteButton ( ) ;
67+ const labelTypeValueHolder = document . createElement ( " div" ) ;
68+ labelTypeValueHolder . classList . add ( " label-type-values" ) ;
69+ const addButton = UiElementFactory . buildAddButton ( " Value" ) ;
70+ addButton . classList . add ( " label-type-value-add" ) ;
71+
72+ nameInput . value = labelType . name ;
73+ nameInput . placeholder = " Label Type Name" ;
74+ nameInput . oninput = ( e : InputEvent ) => this . onInputHandler ( e , nameInput ) ;
75+ setTimeout ( ( ) => dynamicallySetInputSize ( nameInput ) , 0 ) ;
7376 nameInput . onchange = ( ) => {
74- this . labelTypeRegistry . updateLabelTypeName ( labelType . id , nameInput . value )
75- }
77+ this . labelTypeRegistry . updateLabelTypeName ( labelType . id , nameInput . value ) ;
78+ } ;
7679
7780 for ( let i = 0 ; i < labelType . values . length ; i ++ ) {
78- labelTypeValueHolder . appendChild ( this . buildLabelTypeValue ( labelType , i ) )
81+ labelTypeValueHolder . appendChild ( this . buildLabelTypeValue ( labelType , i ) ) ;
7982 }
8083
8184 addButton . onclick = ( ) => {
82- this . labelTypeRegistry . registerLabelTypeValue ( labelType . id , '' )
83- }
85+ this . labelTypeRegistry . registerLabelTypeValue ( labelType . id , "" ) ;
86+ } ;
8487
8588 deleteButton . onclick = ( ) => {
86- this . labelTypeRegistry . unregisterLabelType ( labelType . id )
87- }
89+ this . labelTypeRegistry . unregisterLabelType ( labelType . id ) ;
90+ } ;
8891
89- section . appendChild ( nameInput )
90- section . appendChild ( deleteButton )
91- section . appendChild ( labelTypeValueHolder )
92- section . appendChild ( addButton )
92+ section . appendChild ( nameInput ) ;
93+ section . appendChild ( deleteButton ) ;
94+ section . appendChild ( labelTypeValueHolder ) ;
95+ section . appendChild ( addButton ) ;
9396
94- return section
97+ return section ;
9598 }
9699
97100 private buildLabelTypeValue ( labelType : LabelType , valueIndex : number ) {
98- const holder = document . createElement ( ' div' ) ;
99- holder . classList . add ( ' label-type-value' )
100- const nameInput = document . createElement ( ' input' ) ;
101- nameInput . classList . add ( ' label-type-value-name' )
102- const deleteButton = UiElementFactory . buildDeleteButton ( )
101+ const holder = document . createElement ( " div" ) ;
102+ holder . classList . add ( " label-type-value" ) ;
103+ const nameInput = document . createElement ( " input" ) ;
104+ nameInput . classList . add ( " label-type-value-name" ) ;
105+ const deleteButton = UiElementFactory . buildDeleteButton ( ) ;
103106
104- const value = labelType . values [ valueIndex ]
107+ const value = labelType . values [ valueIndex ] ;
105108
106-
107- nameInput . value = value . text
108- nameInput . placeholder = 'Value'
109- nameInput . oninput = ( e : InputEvent ) => this . onInputHandler ( e , nameInput )
110- setTimeout ( ( ) => dynamicallySetInputSize ( nameInput ) , 0 )
109+ nameInput . value = value . text ;
110+ nameInput . placeholder = "Value" ;
111+ nameInput . oninput = ( e : InputEvent ) => this . onInputHandler ( e , nameInput ) ;
112+ setTimeout ( ( ) => dynamicallySetInputSize ( nameInput ) , 0 ) ;
111113
112114 nameInput . onchange = ( ) => {
113- this . labelTypeRegistry . updateLabelTypeValueText ( labelType . id , value . id , nameInput . value )
114- }
115+ this . labelTypeRegistry . updateLabelTypeValueText ( labelType . id , value . id , nameInput . value ) ;
116+ } ;
115117
116118 deleteButton . onclick = ( ) => {
117- this . labelTypeRegistry . unregisterLabelTypeValue ( labelType . id , value . id )
118- }
119+ this . labelTypeRegistry . unregisterLabelTypeValue ( labelType . id , value . id ) ;
120+ } ;
121+
122+ // Allow dragging to create a label assignment
123+ nameInput . draggable = true ;
124+ nameInput . ondragstart = ( event ) => {
125+ const assignment : LabelAssignment = {
126+ labelTypeId : labelType . id ,
127+ labelTypeValueId : value . id ,
128+ } ;
129+ const assignmentJson = JSON . stringify ( assignment ) ;
130+ event . dataTransfer ?. setData ( LABEL_ASSIGNMENT_MIME_TYPE , assignmentJson ) ;
131+ } ;
132+
133+ // Only edit on double click
134+ nameInput . onclick = ( ) => {
135+ if ( nameInput . getAttribute ( "clicked" ) === "true" ) {
136+ return ;
137+ }
138+
139+ nameInput . setAttribute ( "clicked" , "true" ) ;
140+ setTimeout ( ( ) => {
141+ if ( nameInput . getAttribute ( "clicked" ) === "true" ) {
142+ this . actionDispatcher . dispatch (
143+ AddLabelAssignmentAction . create ( {
144+ labelTypeId : labelType . id ,
145+ labelTypeValueId : value . id ,
146+ } ) ,
147+ ) ;
148+ nameInput . removeAttribute ( "clicked" ) ;
149+ }
150+ } , 500 ) ;
151+ } ;
152+ nameInput . ondblclick = ( ) => {
153+ nameInput . removeAttribute ( "clicked" ) ;
154+ nameInput . focus ( ) ;
155+ } ;
156+ nameInput . onfocus = ( event ) => {
157+ // we check for the single click here, since this gets triggered before the ondblclick event
158+ if ( nameInput . getAttribute ( "clicked" ) !== "true" ) {
159+ event . preventDefault ( ) ;
160+ // the blur needs to occur with a delay, as otherwise chromium browsers prevent the drag
161+ setTimeout ( ( ) => {
162+ nameInput . blur ( ) ;
163+ } , 0 ) ;
164+ }
165+ } ;
119166
120- holder . appendChild ( nameInput )
121- holder . appendChild ( deleteButton )
122- return holder
167+ holder . appendChild ( nameInput ) ;
168+ holder . appendChild ( deleteButton ) ;
169+ return holder ;
123170 }
124171
125172 private onInputHandler ( event : InputEvent , input : HTMLInputElement ) {
126173 if ( ! event . data ?. match ( / ^ [ a - z A - Z 0 - 9 ] * $ / ) ) {
127- event . preventDefault ( )
174+ event . preventDefault ( ) ;
128175 }
129- dynamicallySetInputSize ( input )
176+ dynamicallySetInputSize ( input ) ;
130177 }
131- }
178+ }
0 commit comments