Allow partial text selection in gr-download-dialog

In gr-download-dialog, clicking anywhere in a command input box
previously auto-selected the entire command string. This prevented
users from partially selecting and copying text (e.g. only copying
the patchset ref string).

Add a disable-auto-select property to gr-copy-clipboard,
gr-shell-command, and gr-download-commands, and enable it on
gr-download-dialog so standard text selection works without
auto-selecting on click.

Google-Bug-Id: b/529619831
Release-Notes: Allow partial text selection when copying download patch commands
Change-Id: Ieb08cf110f90b9e293f0c901a8ba78585825701e
diff --git a/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog.ts b/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog.ts
index 95df2fac..f808b1c 100644
--- a/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog.ts
+++ b/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog.ts
@@ -168,6 +168,7 @@
           .commands=${this.computeDownloadCommands()}
           .schemes=${this.schemes}
           .selectedScheme=${this.selectedScheme}
+          .disableAutoSelect=${true}
           show-keyboard-shortcut-tooltips
           @selected-scheme-changed=${(e: BindValueChangeEvent) => {
             this.selectedScheme = e.detail.value;
diff --git a/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog_test.ts b/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog_test.ts
index c107c20..438e151 100644
--- a/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog_test.ts
+++ b/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog_test.ts
@@ -122,6 +122,7 @@
       </section>
       <section class="hidden">
         <gr-download-commands
+          disable-auto-select=""
           id="downloadCommands"
           show-keyboard-shortcut-tooltips=""
         >
@@ -234,6 +235,14 @@
       await element.updateComplete;
     });
 
+    test('passes disableAutoSelect to gr-download-commands', () => {
+      const commands = queryAndAssert<GrDownloadCommands>(
+        element,
+        '#downloadCommands'
+      );
+      assert.isTrue(commands.disableAutoSelect);
+    });
+
     test('focuses on first copy link', async () => {
       const focusStub = sinon.stub(
         queryAndAssert<GrDownloadCommands>(element, '#downloadCommands'),
diff --git a/polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard.ts b/polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard.ts
index 0ee4aa3..bfc6462 100644
--- a/polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard.ts
+++ b/polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard.ts
@@ -52,6 +52,9 @@
   @property({type: Boolean, reflect: true})
   hideInput = false;
 
+  @property({type: Boolean, attribute: 'disable-auto-select', reflect: true})
+  disableAutoSelect = false;
+
   @property({type: String})
   label?: string;
 
@@ -216,6 +219,7 @@
   }
 
   private handleInputClick(e: MouseEvent) {
+    if (this.disableAutoSelect) return;
     e.preventDefault();
     const rootTarget = e.composedPath()[0];
     (rootTarget as HTMLInputElement).select();
diff --git a/polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard_test.ts b/polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard_test.ts
index b50ecfd..acc1180 100644
--- a/polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard_test.ts
+++ b/polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard_test.ts
@@ -128,6 +128,22 @@
     assert.equal(mdOutlinedTextField.selectionEnd, element.text!.length - 1);
   });
 
+  test('handleInputClick with disableAutoSelect', async () => {
+    element.disableAutoSelect = true;
+    await element.updateComplete;
+
+    const mdOutlinedTextField = queryAndAssert<MdOutlinedTextField>(
+      element,
+      'md-outlined-text-field'
+    );
+    mdOutlinedTextField.selectionStart = 0;
+    mdOutlinedTextField.selectionEnd = 0;
+
+    mdOutlinedTextField.click();
+    assert.equal(mdOutlinedTextField.selectionStart, 0);
+    assert.equal(mdOutlinedTextField.selectionEnd, 0);
+  });
+
   test('hideInput', async () => {
     const mdOutlinedTextField = queryAndAssert<MdOutlinedTextField>(
       element,
diff --git a/polygerrit-ui/app/elements/shared/gr-download-commands/gr-download-commands.ts b/polygerrit-ui/app/elements/shared/gr-download-commands/gr-download-commands.ts
index 9a7cabc..30defc5 100644
--- a/polygerrit-ui/app/elements/shared/gr-download-commands/gr-download-commands.ts
+++ b/polygerrit-ui/app/elements/shared/gr-download-commands/gr-download-commands.ts
@@ -54,6 +54,9 @@
   @property({type: Boolean, attribute: 'show-keyboard-shortcut-tooltips'})
   showKeyboardShortcutTooltips = false;
 
+  @property({type: Boolean, attribute: 'disable-auto-select', reflect: true})
+  disableAutoSelect = false;
+
   // Private but used in tests.
   readonly getUserModel = resolve(this, userModelToken);
 
@@ -171,6 +174,7 @@
         .label=${command.title}
         .command=${command.command}
         .tooltip=${this.computeTooltip(index)}
+        .disableAutoSelect=${this.disableAutoSelect}
       ></gr-shell-command>
     `;
   }
diff --git a/polygerrit-ui/app/elements/shared/gr-download-commands/gr-download-commands_test.ts b/polygerrit-ui/app/elements/shared/gr-download-commands/gr-download-commands_test.ts
index 05011f8f..3f3b4bc 100644
--- a/polygerrit-ui/app/elements/shared/gr-download-commands/gr-download-commands_test.ts
+++ b/polygerrit-ui/app/elements/shared/gr-download-commands/gr-download-commands_test.ts
@@ -97,6 +97,16 @@
       assert.isTrue(focusStub.called);
     });
 
+    test('passes disableAutoSelect to gr-shell-command', async () => {
+      element.disableAutoSelect = true;
+      await element.updateComplete;
+      const shellCommand = queryAndAssert<GrShellCommand>(
+        element,
+        'gr-shell-command'
+      );
+      assert.isTrue(shellCommand.disableAutoSelect);
+    });
+
     test('element visibility', async () => {
       assert.isFalse(isHidden(queryAndAssert(element, 'md-tabs')));
       assert.isFalse(isHidden(queryAndAssert(element, '.commands')));
diff --git a/polygerrit-ui/app/elements/shared/gr-shell-command/gr-shell-command.ts b/polygerrit-ui/app/elements/shared/gr-shell-command/gr-shell-command.ts
index 0c9be74..54aecb3 100644
--- a/polygerrit-ui/app/elements/shared/gr-shell-command/gr-shell-command.ts
+++ b/polygerrit-ui/app/elements/shared/gr-shell-command/gr-shell-command.ts
@@ -27,6 +27,9 @@
   @property({type: String})
   tooltip = '';
 
+  @property({type: Boolean, attribute: 'disable-auto-select', reflect: true})
+  disableAutoSelect = false;
+
   static override get styles() {
     return [
       sharedStyles,
@@ -73,6 +76,7 @@
           .text=${this.command}
           hasTooltip
           buttonTitle=${this.tooltip}
+          .disableAutoSelect=${this.disableAutoSelect}
         ></gr-copy-clipboard>
       </div>`;
   }
diff --git a/polygerrit-ui/app/elements/shared/gr-shell-command/gr-shell-command_test.ts b/polygerrit-ui/app/elements/shared/gr-shell-command/gr-shell-command_test.ts
index 1e0ff11..8fb66f5 100644
--- a/polygerrit-ui/app/elements/shared/gr-shell-command/gr-shell-command_test.ts
+++ b/polygerrit-ui/app/elements/shared/gr-shell-command/gr-shell-command_test.ts
@@ -44,4 +44,14 @@
     await element.focusOnCopy();
     assert.isTrue(focusStub.called);
   });
+
+  test('passes disableAutoSelect to gr-copy-clipboard', async () => {
+    element.disableAutoSelect = true;
+    await element.updateComplete;
+    const copyClipboard = queryAndAssert<GrCopyClipboard>(
+      element,
+      'gr-copy-clipboard'
+    );
+    assert.isTrue(copyClipboard.disableAutoSelect);
+  });
 });