22// Use of this source code is governed by a BSD-style license that can be
33// found in the LICENSE file.
44
5+ import * as Host from '../../core/host/host.js' ;
6+ import * as i18n from '../../core/i18n/i18n.js' ;
57import * as Platform from '../../core/platform/platform.js' ;
68import type * as Workspace from '../../models/workspace/workspace.js' ;
79import * as WorkspaceDiff from '../../models/workspace_diff/workspace_diff.js' ;
@@ -14,14 +16,28 @@ import * as PanelUtils from '../utils/utils.js';
1416
1517import combinedDiffViewStyles from './combinedDiffView.css.js' ;
1618
19+ const COPIED_TO_CLIPBOARD_TEXT_TIMEOUT_MS = 1000 ;
20+
1721const { html} = Lit ;
1822
23+ const UIStrings = {
24+ /**
25+ * @description The title of the button after it was pressed and the text was copied to clipboard.
26+ */
27+ copied : 'Copied to clipboard' ,
28+ } as const ;
29+
30+ const str_ = i18n . i18n . registerUIStrings ( 'panels/changes/CombinedDiffView.ts' , UIStrings ) ;
31+ const i18nString = i18n . i18n . getLocalizedString . bind ( undefined , str_ ) ;
32+
1933interface SingleDiffViewInput {
2034 fileName : string ;
35+ fileUrl : string ;
2136 mimeType : string ;
2237 icon : HTMLElement ;
2338 diff : Diff . Diff . DiffArray ;
24- onCopy : ( diff : Diff . Diff . DiffArray ) => void ;
39+ copied : boolean ;
40+ onCopy : ( fileUrl : string , diff : Diff . Diff . DiffArray ) => void ;
2541}
2642
2743export interface ViewInput {
@@ -31,7 +47,8 @@ export interface ViewInput {
3147type View = ( input : ViewInput , output : undefined , target : HTMLElement ) => void ;
3248
3349function renderSingleDiffView ( singleDiffViewInput : SingleDiffViewInput ) : Lit . TemplateResult {
34- const { fileName, mimeType, icon, diff, onCopy} = singleDiffViewInput ;
50+ const { fileName, fileUrl, mimeType, icon, diff, copied, onCopy} = singleDiffViewInput ;
51+
3552 return html `
3653 < details open >
3754 < summary >
@@ -41,13 +58,15 @@ function renderSingleDiffView(singleDiffViewInput: SingleDiffViewInput): Lit.Tem
4158 < span class ="file-name "> ${ fileName } </ span >
4259 </ div >
4360 < div class ="summary-right ">
44- < devtools-button
45- title =${ 'Copy' }
46- .size =${ Buttons . Button . Size . SMALL }
47- .iconName=${ 'copy' }
48- .jslogContext=${ 'combined-diff-view.copy' }
49- .variant=${ Buttons . Button . Variant . ICON }
50- @click=${ ( ) => onCopy ( diff ) } > </ devtools-button >
61+ ${ copied ? html `< span class ="copied "> ${ i18nString ( UIStrings . copied ) } </ span > ` : html `
62+ < devtools-button
63+ title =${ 'Copy' }
64+ .size =${ Buttons . Button . Size . SMALL }
65+ .iconName=${ 'copy' }
66+ .jslogContext=${ 'combined-diff-view.copy' }
67+ .variant=${ Buttons . Button . Variant . ICON }
68+ @click=${ ( ) => onCopy ( fileUrl , diff ) } > </ devtools-button >
69+ ` }
5170 </ div >
5271 </ summary >
5372 < div class ='diff-view-container '>
@@ -62,6 +81,7 @@ function renderSingleDiffView(singleDiffViewInput: SingleDiffViewInput): Lit.Tem
6281export class CombinedDiffView extends UI . Widget . Widget {
6382 #workspaceDiff?: WorkspaceDiff . WorkspaceDiff . WorkspaceDiffImpl ;
6483 #modifiedUISourceCodes: Workspace . UISourceCode . UISourceCode [ ] = [ ] ;
84+ #copiedFiles: Record < string , boolean > = { } ;
6585 #view: View ;
6686 constructor ( element ?: HTMLElement , view : View = ( input , output , target ) => {
6787 Lit . render (
@@ -94,8 +114,15 @@ export class CombinedDiffView extends UI.Widget.Widget {
94114 void this . #initializeModifiedUISourceCodes( ) ;
95115 }
96116
97- #onCopyDiff( ) : void {
98- // TODO(ergunsh): Implement copying diff
117+ async #onCopyDiff( fileUrl : string , diff : Diff . Diff . DiffArray ) : Promise < void > {
118+ const changes = await PanelUtils . PanelUtils . formatCSSChangesFromDiff ( diff ) ;
119+ Host . InspectorFrontendHost . InspectorFrontendHostInstance . copyText ( changes ) ;
120+ this . #copiedFiles[ fileUrl ] = true ;
121+ this . requestUpdate ( ) ;
122+ setTimeout ( ( ) => {
123+ delete this . #copiedFiles[ fileUrl ] ;
124+ this . requestUpdate ( ) ;
125+ } , COPIED_TO_CLIPBOARD_TEXT_TIMEOUT_MS ) ;
99126 }
100127
101128 async #initializeModifiedUISourceCodes( ) : Promise < void > {
@@ -151,8 +178,10 @@ export class CombinedDiffView extends UI.Widget.Widget {
151178 return {
152179 diff : diff as Diff . Diff . DiffArray , // We already filter above the ones that does not have `diff`.
153180 fileName : `${ uiSourceCode . isDirty ( ) ? '*' : '' } ${ uiSourceCode . displayName ( ) } ` ,
181+ fileUrl : uiSourceCode . url ( ) ,
154182 mimeType : uiSourceCode . mimeType ( ) ,
155183 icon : PanelUtils . PanelUtils . getIconForSourceFile ( uiSourceCode , { width : 18 , height : 18 } ) ,
184+ copied : this . #copiedFiles[ uiSourceCode . url ( ) ] ,
156185 onCopy : this . #onCopyDiff. bind ( this ) ,
157186 } ;
158187 } )
0 commit comments