Merge "Add a fireEvent util"
diff --git a/Documentation/rest-api-changes.txt b/Documentation/rest-api-changes.txt
index 43c3b9e..1a5920f 100644
--- a/Documentation/rest-api-changes.txt
+++ b/Documentation/rest-api-changes.txt
@@ -1388,6 +1388,8 @@
The destination branch must be provided in the request body inside a
link:#move-input[MoveInput] entity.
+Only veto votes that are blocking the change from submission are moved to
+the destination branch by default.
.Request
----
@@ -7354,6 +7356,11 @@
|`destination_branch`||Destination branch
|`message` |optional|
A message to be posted in this change's comments
+|`keep_all_labels` |optional, defaults to false|
+By default, only veto votes that are blocking the change from submission are moved to
+the destination branch. Using this option is only allowed for administrators,
+because it can affect the submission behaviour of the change (depending on the label access
+configuration and submissions rules).
|===========================
[[notify-info]]
diff --git a/java/com/google/gerrit/extensions/api/changes/MoveInput.java b/java/com/google/gerrit/extensions/api/changes/MoveInput.java
index 795642a..3d82990 100644
--- a/java/com/google/gerrit/extensions/api/changes/MoveInput.java
+++ b/java/com/google/gerrit/extensions/api/changes/MoveInput.java
@@ -17,4 +17,14 @@
public class MoveInput {
public String message;
public String destinationBranch;
+ /**
+ * Whether or not to keep all votes in the destination branch. Keeping the votes can be confusing
+ * in the context of the destination branch, see
+ * https://gerrit-review.googlesource.com/c/gerrit/+/129171. That is why only the users with
+ * {@link com.google.gerrit.server.permissions.GlobalPermission#ADMINISTRATE_SERVER} permissions
+ * can use this option.
+ *
+ * <p>By default, only the veto votes that are blocking the change from submission are moved.
+ */
+ public boolean keepAllVotes;
}
diff --git a/java/com/google/gerrit/server/restapi/change/Move.java b/java/com/google/gerrit/server/restapi/change/Move.java
index 577174f..8ec394c 100644
--- a/java/com/google/gerrit/server/restapi/change/Move.java
+++ b/java/com/google/gerrit/server/restapi/change/Move.java
@@ -52,6 +52,7 @@
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.notedb.ChangeUpdate;
+import com.google.gerrit.server.permissions.GlobalPermission;
import com.google.gerrit.server.permissions.PermissionBackend;
import com.google.gerrit.server.permissions.PermissionBackendException;
import com.google.gerrit.server.project.ProjectCache;
@@ -140,6 +141,18 @@
// Not allowed to move if the current patch set is locked.
psUtil.checkPatchSetNotLocked(rsrc.getNotes());
+ // Keeping all votes can be confusing in the context of the destination branch, see the
+ // discussion in
+ // https://gerrit-review.googlesource.com/c/gerrit/+/129171
+ // Only administrators are allowed to keep all labels at their own risk.
+ try {
+ if (input.keepAllVotes) {
+ permissionBackend.user(caller).check(GlobalPermission.ADMINISTRATE_SERVER);
+ }
+ } catch (AuthException denied) {
+ throw new AuthException("move is not permitted with keepAllVotes option", denied);
+ }
+
// Move requires abandoning this change, and creating a new change.
try {
rsrc.permissions().check(ABANDON);
@@ -226,7 +239,9 @@
update.setBranch(newDestKey.branch());
change.setDest(newDestKey);
- updateApprovals(ctx, update, psId, projectKey);
+ if (!input.keepAllVotes) {
+ updateApprovals(ctx, update, psId, projectKey);
+ }
StringBuilder msgBuf = new StringBuilder();
msgBuf.append("Change destination moved from ");
diff --git a/javatests/com/google/gerrit/acceptance/rest/change/MoveChangeIT.java b/javatests/com/google/gerrit/acceptance/rest/change/MoveChangeIT.java
index d5881ea..19e36f2 100644
--- a/javatests/com/google/gerrit/acceptance/rest/change/MoveChangeIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/change/MoveChangeIT.java
@@ -16,15 +16,19 @@
import static com.google.common.truth.Truth.assertThat;
import static com.google.gerrit.acceptance.GitUtil.pushHead;
+import static com.google.gerrit.acceptance.testsuite.project.TestProjectUpdate.allow;
import static com.google.gerrit.acceptance.testsuite.project.TestProjectUpdate.allowLabel;
import static com.google.gerrit.acceptance.testsuite.project.TestProjectUpdate.block;
import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS;
+import static com.google.gerrit.server.project.testing.TestLabels.value;
import static com.google.gerrit.testing.GerritJUnit.assertThrows;
+import com.google.common.collect.ImmutableList;
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.GitUtil;
import com.google.gerrit.acceptance.NoHttpd;
import com.google.gerrit.acceptance.PushOneCommit;
+import com.google.gerrit.acceptance.TestAccount;
import com.google.gerrit.acceptance.config.GerritConfig;
import com.google.gerrit.acceptance.testsuite.project.ProjectOperations;
import com.google.gerrit.acceptance.testsuite.request.RequestScopeOperations;
@@ -190,7 +194,7 @@
.update();
AuthException thrown =
assertThrows(AuthException.class, () -> move(r.getChangeId(), newBranch.branch()));
- assertThat(thrown).hasMessageThat().contains("move not permitted");
+ assertThat(thrown).hasMessageThat().isEqualTo("move not permitted");
}
@Test
@@ -210,7 +214,7 @@
requestScopeOperations.setApiUser(user.id());
AuthException thrown =
assertThrows(AuthException.class, () -> move(r.getChangeId(), newBranch.branch()));
- assertThat(thrown).hasMessageThat().contains("move not permitted");
+ assertThat(thrown).hasMessageThat().isEqualTo("move not permitted");
}
@Test
@@ -269,6 +273,224 @@
}
@Test
+ public void moveChangeKeepAllVotesOnlyAllowedForAdmins() throws Exception {
+ // Keep all votes options is only permitted for admins.
+ BranchNameKey destinationBranch = BranchNameKey.create(project, "dest");
+ createBranch(destinationBranch);
+ BranchNameKey sourceBranch = BranchNameKey.create(project, "source");
+ createBranch(sourceBranch);
+ String changeId = createChangeInBranch(sourceBranch.branch()).getChangeId();
+
+ // Grant change permissions to the registered users.
+ projectOperations
+ .project(project)
+ .forUpdate()
+ .add(allow(Permission.PUSH).ref(destinationBranch.branch()).group(REGISTERED_USERS))
+ .update();
+ projectOperations
+ .project(project)
+ .forUpdate()
+ .add(allow(Permission.ABANDON).ref(sourceBranch.branch()).group(REGISTERED_USERS))
+ .update();
+
+ requestScopeOperations.setApiUser(user.id());
+
+ AuthException thrown =
+ assertThrows(
+ AuthException.class, () -> move(changeId, destinationBranch.shortName(), true));
+ assertThat(thrown).hasMessageThat().isEqualTo("move is not permitted with keepAllVotes option");
+
+ requestScopeOperations.setApiUser(admin.id());
+
+ move(changeId, destinationBranch.branch(), true);
+ assertThat(info(changeId).branch).isEqualTo(destinationBranch.shortName());
+ }
+
+ @Test
+ public void moveChangeKeepAllVotesNoLabelInDestination() throws Exception {
+ BranchNameKey destinationBranch = BranchNameKey.create(project, "dest");
+ createBranch(destinationBranch);
+ BranchNameKey sourceBranch = BranchNameKey.create(project, "source");
+ createBranch(sourceBranch);
+
+ String testLabelA = "Label-A";
+ // The label has the range [-1; 1]
+ configLabel(testLabelA, LabelFunction.NO_BLOCK, ImmutableList.of(sourceBranch.branch()));
+ // Registered users have permissions for the entire range [-1; 1] on all branches.
+ projectOperations
+ .project(project)
+ .forUpdate()
+ .add(allowLabel(testLabelA).ref("refs/heads/*").group(REGISTERED_USERS).range(-1, +1))
+ .update();
+
+ String changeId = createChangeInBranch(sourceBranch.branch()).getChangeId();
+ requestScopeOperations.setApiUser(user.id());
+ ReviewInput userReviewInput = new ReviewInput();
+ userReviewInput.label(testLabelA, 1);
+ gApi.changes().id(changeId).current().review(userReviewInput);
+
+ assertLabelVote(user, changeId, testLabelA, (short) 1);
+
+ requestScopeOperations.setApiUser(admin.id());
+ assertThat(atrScope.get().getUser().getAccountId()).isEqualTo(admin.id());
+
+ // Move the change to the destination branch.
+ assertThat(info(changeId).branch).isEqualTo(sourceBranch.shortName());
+ move(changeId, destinationBranch.shortName(), true);
+ assertThat(info(changeId).branch).isEqualTo(destinationBranch.shortName());
+
+ // Label is missing in the destination branch.
+ assertThat(gApi.changes().id(changeId).current().reviewer(user.email()).votes()).isEmpty();
+
+ // Move the change back to the source, the label is kept.
+ move(changeId, sourceBranch.shortName(), true);
+ assertThat(info(changeId).branch).isEqualTo(sourceBranch.shortName());
+ assertLabelVote(user, changeId, testLabelA, (short) 1);
+ }
+
+ @Test
+ public void moveChangeKeepAllVotesOutOfUserPermissionRange() throws Exception {
+ BranchNameKey destinationBranch = BranchNameKey.create(project, "dest");
+ createBranch(destinationBranch);
+ BranchNameKey sourceBranch = BranchNameKey.create(project, "source");
+ createBranch(sourceBranch);
+
+ String testLabelA = "Label-A";
+ // The label has the range [-2; 2]
+ configLabel(
+ project,
+ testLabelA,
+ LabelFunction.NO_BLOCK,
+ value(2, "Passes"),
+ value(1, "Mostly ok"),
+ value(0, "No score"),
+ value(-1, "Needs work"),
+ value(-2, "Failed"));
+ // Registered users have [-2; 2] permissions on the source.
+ projectOperations
+ .project(project)
+ .forUpdate()
+ .add(
+ allowLabel(testLabelA).ref(sourceBranch.branch()).group(REGISTERED_USERS).range(-2, +2))
+ .update();
+
+ // Registered users have [-1; 1] permissions on the destination.
+ projectOperations
+ .project(project)
+ .forUpdate()
+ .add(
+ allowLabel(testLabelA)
+ .ref(destinationBranch.branch())
+ .group(REGISTERED_USERS)
+ .range(-1, +1))
+ .update();
+
+ String changeId = createChangeInBranch(sourceBranch.branch()).getChangeId();
+ requestScopeOperations.setApiUser(user.id());
+ // Vote within the range of the source branch.
+ ReviewInput userReviewInput = new ReviewInput();
+ userReviewInput.label(testLabelA, 2);
+ gApi.changes().id(changeId).current().review(userReviewInput);
+
+ assertLabelVote(user, changeId, testLabelA, (short) 2);
+
+ requestScopeOperations.setApiUser(admin.id());
+ assertThat(atrScope.get().getUser().getAccountId()).isEqualTo(admin.id());
+
+ // Move the change to the destination branch.
+ assertThat(info(changeId).branch).isEqualTo(sourceBranch.shortName());
+ move(changeId, destinationBranch.branch(), true);
+ // User does not have label permissions for the same vote on the destination branch.
+ requestScopeOperations.setApiUser(user.id());
+ AuthException thrown =
+ assertThrows(
+ AuthException.class,
+ () -> gApi.changes().id(changeId).current().review(userReviewInput));
+ assertThat(thrown)
+ .hasMessageThat()
+ .isEqualTo(String.format("Applying label \"%s\": 2 is restricted", testLabelA));
+
+ // Label is kept even though the user's permission range is different from the source.
+ // Since we do not squash users votes based on the destination branch access label
+ // configuration, this is working as intended.
+ // It's the same behavior as when a project owner reduces user's permission range on label.
+ // Administrators should take this into account.
+ assertThat(info(changeId).branch).isEqualTo(destinationBranch.shortName());
+ assertLabelVote(user, changeId, testLabelA, (short) 2);
+
+ requestScopeOperations.setApiUser(admin.id());
+ // Move the change back to the source, the label is kept.
+ move(changeId, sourceBranch.shortName(), true);
+ assertThat(info(changeId).branch).isEqualTo(sourceBranch.shortName());
+ assertLabelVote(user, changeId, testLabelA, (short) 2);
+ }
+
+ @Test
+ public void moveKeepAllVotesCanMoveAllInRange() throws Exception {
+ BranchNameKey destinationBranch = BranchNameKey.create(project, "dest");
+ createBranch(destinationBranch);
+ BranchNameKey sourceBranch = BranchNameKey.create(project, "source");
+ createBranch(sourceBranch);
+
+ // The non-block label has the range [-2; 2]
+ String testLabelA = "Label-A";
+ configLabel(
+ project,
+ testLabelA,
+ LabelFunction.NO_BLOCK,
+ value(2, "Passes"),
+ value(1, "Mostly ok"),
+ value(0, "No score"),
+ value(-1, "Needs work"),
+ value(-2, "Failed"));
+
+ // Registered users have [-2; 2] permissions on all branches.
+ projectOperations
+ .project(project)
+ .forUpdate()
+ .add(allowLabel(testLabelA).ref("refs/heads/*").group(REGISTERED_USERS).range(-2, +2))
+ .update();
+
+ String changeId = createChangeInBranch(sourceBranch.branch()).getChangeId();
+
+ for (int vote = -2; vote <= 2; vote++) {
+ TestAccount testUser = accountCreator.create("TestUser" + vote);
+ requestScopeOperations.setApiUser(testUser.id());
+ ReviewInput userReviewInput = new ReviewInput();
+ userReviewInput.label(testLabelA, vote);
+ gApi.changes().id(changeId).current().review(userReviewInput);
+ }
+
+ assertThat(
+ gApi.changes().id(changeId).current().votes().get(testLabelA).stream()
+ .map(approvalInfo -> approvalInfo.value)
+ .collect(ImmutableList.toImmutableList()))
+ .containsExactly(-2, -1, 1, 2);
+
+ requestScopeOperations.setApiUser(admin.id());
+ // Move the change to the destination branch.
+ assertThat(info(changeId).branch).isEqualTo(sourceBranch.shortName());
+ move(changeId, destinationBranch.shortName(), true);
+ assertThat(info(changeId).branch).isEqualTo(destinationBranch.shortName());
+
+ // All votes are kept
+ assertThat(
+ gApi.changes().id(changeId).current().votes().get(testLabelA).stream()
+ .map(approvalInfo -> approvalInfo.value)
+ .collect(ImmutableList.toImmutableList()))
+ .containsExactly(-2, -1, 1, 2);
+
+ // Move the change back to the source, the label is kept.
+ move(changeId, sourceBranch.shortName(), true);
+ assertThat(info(changeId).branch).isEqualTo(sourceBranch.shortName());
+ assertThat(
+ gApi.changes().id(changeId).current().votes().get(testLabelA).stream()
+ .map(approvalInfo -> approvalInfo.value)
+ .collect(ImmutableList.toImmutableList()))
+ .containsExactly(-2, -1, 1, 2);
+ }
+
+ @Test
public void moveChangeOnlyKeepVetoVotes() throws Exception {
// A vote for a label will be kept after moving if the label's function is *WithBlock and the
// vote holds the minimum value.
@@ -394,10 +616,28 @@
gApi.changes().id(changeId).move(in);
}
+ private void move(String changeId, String destination, boolean keepAllVotes)
+ throws RestApiException {
+ MoveInput in = new MoveInput();
+ in.destinationBranch = destination;
+ in.keepAllVotes = keepAllVotes;
+ gApi.changes().id(changeId).move(in);
+ }
+
private PushOneCommit.Result createChange(String branch, String changeId) throws Exception {
PushOneCommit push = pushFactory.create(admin.newIdent(), testRepo, changeId);
PushOneCommit.Result result = push.to("refs/for/" + branch);
result.assertOkStatus();
return result;
}
+
+ private PushOneCommit.Result createChangeInBranch(String branch) throws Exception {
+ return createChange("refs/for/" + branch);
+ }
+
+ private void assertLabelVote(TestAccount user, String changeId, String label, short vote)
+ throws Exception {
+ assertThat(gApi.changes().id(changeId).current().reviewer(user.email()).votes())
+ .containsEntry(label, vote);
+ }
}
diff --git a/polygerrit-ui/app/elements/core/gr-key-binding-display/gr-key-binding-display.css.ts b/polygerrit-ui/app/elements/core/gr-key-binding-display/gr-key-binding-display.css.ts
deleted file mode 100644
index ccba289..0000000
--- a/polygerrit-ui/app/elements/core/gr-key-binding-display/gr-key-binding-display.css.ts
+++ /dev/null
@@ -1,30 +0,0 @@
-/**
- * @license
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import {css} from 'lit-element';
-
-export const cssTemplate = css`
- .key {
- background-color: var(--chip-background-color);
- color: var(--primary-text-color);
- border: 1px solid var(--border-color);
- border-radius: var(--border-radius);
- display: inline-block;
- font-weight: var(--font-weight-bold);
- padding: var(--spacing-xxs) var(--spacing-m);
- text-align: center;
- }
-`;
diff --git a/polygerrit-ui/app/elements/core/gr-key-binding-display/gr-key-binding-display.ts b/polygerrit-ui/app/elements/core/gr-key-binding-display/gr-key-binding-display.ts
index 091684f..796a167 100644
--- a/polygerrit-ui/app/elements/core/gr-key-binding-display/gr-key-binding-display.ts
+++ b/polygerrit-ui/app/elements/core/gr-key-binding-display/gr-key-binding-display.ts
@@ -14,11 +14,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import {html} from 'lit-html';
-import {GrLitElement} from '../../lit/gr-lit-element';
-import {customElement, property} from 'lit-element';
-import {cssTemplate} from './gr-key-binding-display.css';
-import {sharedStyles} from '../../../styles/shared-styles';
+import '../../../styles/shared-styles';
+import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
+import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
+import {PolymerElement} from '@polymer/polymer/polymer-element';
+import {htmlTemplate} from './gr-key-binding-display_html';
+import {customElement, property} from '@polymer/decorators';
declare global {
interface HTMLElementTagNameMap {
@@ -27,30 +28,21 @@
}
@customElement('gr-key-binding-display')
-export class GrKeyBindingDisplay extends GrLitElement {
- static get styles() {
- return [sharedStyles, cssTemplate];
- }
-
- render() {
- const items = this.binding.map((binding, index) => [
- index > 0 ? html` or ` : html``,
- this._computeModifiers(binding).map(
- modifier => html`<span class="key modifier">${modifier}</span> `
- ),
- html`<span class="key">${this._computeKey(binding)}</span>`,
- ]);
- return html`${items}`;
+export class GrKeyBindingDisplay extends GestureEventListeners(
+ LegacyElementMixin(PolymerElement)
+) {
+ static get template() {
+ return htmlTemplate;
}
@property({type: Array})
binding: string[][] = [];
- _computeModifiers(binding: string[]) {
+ _computeModifiers(binding: string[][]) {
return binding.slice(0, binding.length - 1);
}
- _computeKey(binding: string[]) {
+ _computeKey(binding: string[][]) {
return binding[binding.length - 1];
}
}
diff --git a/polygerrit-ui/app/elements/core/gr-key-binding-display/gr-key-binding-display_html.ts b/polygerrit-ui/app/elements/core/gr-key-binding-display/gr-key-binding-display_html.ts
new file mode 100644
index 0000000..251e30f
--- /dev/null
+++ b/polygerrit-ui/app/elements/core/gr-key-binding-display/gr-key-binding-display_html.ts
@@ -0,0 +1,41 @@
+/**
+ * @license
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import {html} from '@polymer/polymer/lib/utils/html-tag';
+
+export const htmlTemplate = html`
+ <style include="shared-styles">
+ .key {
+ background-color: var(--chip-background-color);
+ color: var(--primary-text-color);
+ border: 1px solid var(--border-color);
+ border-radius: var(--border-radius);
+ display: inline-block;
+ font-weight: var(--font-weight-bold);
+ padding: var(--spacing-xxs) var(--spacing-m);
+ text-align: center;
+ }
+ </style>
+ <template is="dom-repeat" items="[[binding]]">
+ <template is="dom-if" if="[[index]]">
+ or
+ </template>
+ <template is="dom-repeat" items="[[_computeModifiers(item)]]" as="modifier">
+ <span class="key modifier">[[modifier]]</span>
+ </template>
+ <span class="key">[[_computeKey(item)]]</span>
+ </template>
+`;
diff --git a/polygerrit-ui/app/elements/core/gr-key-binding-display/gr-key-binding-display_test.ts b/polygerrit-ui/app/elements/core/gr-key-binding-display/gr-key-binding-display_test.js
similarity index 86%
rename from polygerrit-ui/app/elements/core/gr-key-binding-display/gr-key-binding-display_test.ts
rename to polygerrit-ui/app/elements/core/gr-key-binding-display/gr-key-binding-display_test.js
index 875cde8..0c25e6e 100644
--- a/polygerrit-ui/app/elements/core/gr-key-binding-display/gr-key-binding-display_test.ts
+++ b/polygerrit-ui/app/elements/core/gr-key-binding-display/gr-key-binding-display_test.js
@@ -17,12 +17,11 @@
import '../../../test/common-test-setup-karma.js';
import './gr-key-binding-display.js';
-import {GrKeyBindingDisplay} from './gr-key-binding-display.js';
const basicFixture = fixtureFromElement('gr-key-binding-display');
suite('gr-key-binding-display tests', () => {
- let element: GrKeyBindingDisplay;
+ let element;
setup(() => {
element = basicFixture.instantiate();
@@ -46,10 +45,10 @@
test('key with modifiers', () => {
assert.deepEqual(element._computeModifiers(['Ctrl', 'x']), ['Ctrl']);
- assert.deepEqual(element._computeModifiers(['Shift', 'Meta', 'x']), [
- 'Shift',
- 'Meta',
- ]);
+ assert.deepEqual(
+ element._computeModifiers(['Shift', 'Meta', 'x']),
+ ['Shift', 'Meta']);
});
});
});
+
diff --git a/polygerrit-ui/app/styles/shared-styles.ts b/polygerrit-ui/app/styles/shared-styles.ts
index c2baaa9..695ae24 100644
--- a/polygerrit-ui/app/styles/shared-styles.ts
+++ b/polygerrit-ui/app/styles/shared-styles.ts
@@ -15,8 +15,6 @@
* limitations under the License.
*/
-import {css} from 'lit-element';
-
// Mark the file as a module. Otherwise typescript assumes this is a script
// and $_documentContainer is a global variable.
// See: https://www.typescriptlang.org/docs/handbook/modules.html
@@ -24,276 +22,189 @@
const $_documentContainer = document.createElement('template');
-export const sharedStyles = css`
- /* CSS reset */
-
- html,
- body,
- button,
- div,
- span,
- applet,
- object,
- iframe,
- h1,
- h2,
- h3,
- h4,
- h5,
- h6,
- p,
- blockquote,
- pre,
- a,
- abbr,
- acronym,
- address,
- big,
- cite,
- code,
- del,
- dfn,
- em,
- img,
- ins,
- kbd,
- q,
- s,
- samp,
- small,
- strike,
- strong,
- sub,
- sup,
- tt,
- var,
- b,
- u,
- i,
- center,
- dl,
- dt,
- dd,
- ol,
- ul,
- li,
- fieldset,
- form,
- label,
- legend,
- table,
- caption,
- tbody,
- tfoot,
- thead,
- tr,
- th,
- td,
- article,
- aside,
- canvas,
- details,
- embed,
- figure,
- figcaption,
- footer,
- header,
- hgroup,
- main,
- menu,
- nav,
- output,
- ruby,
- section,
- summary,
- time,
- mark,
- audio,
- video {
- border: 0;
- box-sizing: border-box;
- font-size: 100%;
- font: inherit;
- margin: 0;
- padding: 0;
- vertical-align: baseline;
- }
- *::after,
- *::before {
- box-sizing: border-box;
- }
- input {
- background-color: var(--background-color-primary);
- border: 1px solid var(--border-color);
- border-radius: var(--border-radius);
- box-sizing: border-box;
- color: var(--primary-text-color);
- margin: 0;
- padding: var(--spacing-s);
- }
- iron-autogrow-textarea {
- background-color: inherit;
- color: var(--primary-text-color);
- border: 1px solid var(--border-color);
- border-radius: var(--border-radius);
- padding: 0;
- box-sizing: border-box;
- /* iron-autogrow-textarea has a "-webkit-appearance: textarea" :host
- css rule, which prevents overriding the border color. Clear that. */
- -webkit-appearance: none;
-
- --iron-autogrow-textarea: {
- box-sizing: border-box;
- padding: var(--spacing-s);
- }
- }
- a {
- color: var(--link-color);
- }
- input,
- textarea,
- select,
- button {
- font: inherit;
- }
- ol,
- ul {
- list-style: none;
- }
- blockquote,
- q {
- quotes: none;
- }
- blockquote:before,
- blockquote:after,
- q:before,
- q:after {
- content: '';
- content: none;
- }
- table {
- border-collapse: collapse;
- border-spacing: 0;
- }
-
- /* Fonts */
-
- .font-normal {
- font-size: var(--font-size-normal);
- font-weight: var(--font-weight-normal);
- line-height: var(--line-height-normal);
- }
- .font-small {
- font-size: var(--font-size-small);
- font-weight: var(--font-weight-normal);
- line-height: var(--line-height-small);
- }
- .heading-1 {
- font-family: var(--header-font-family);
- font-size: var(--font-size-h1);
- font-weight: var(--font-weight-h1);
- line-height: var(--line-height-h1);
- }
- .heading-2 {
- font-family: var(--header-font-family);
- font-size: var(--font-size-h2);
- font-weight: var(--font-weight-h2);
- line-height: var(--line-height-h2);
- }
- .heading-3 {
- font-family: var(--header-font-family);
- font-size: var(--font-size-h3);
- font-weight: var(--font-weight-h3);
- line-height: var(--line-height-h3);
- }
- iron-icon {
- color: var(--deemphasized-text-color);
- --iron-icon-height: 20px;
- --iron-icon-width: 20px;
- }
-
- /* Stopgap solution until we remove hidden$ attributes. */
-
- :host([hidden]),
- [hidden] {
- display: none !important;
- }
- .separator {
- border-left: 1px solid var(--border-color);
- height: 20px;
- margin: 0 8px;
- }
- .separator.transparent {
- border-color: transparent;
- }
- paper-toggle-button {
- --paper-toggle-button-checked-bar-color: var(--link-color);
- --paper-toggle-button-checked-button-color: var(--link-color);
- }
- paper-tabs {
- font-size: var(--font-size-h3);
- font-weight: var(--font-weight-h3);
- line-height: var(--line-height-h3);
- --paper-font-common-base: {
- font-family: var(--header-font-family);
- -webkit-font-smoothing: initial;
- }
- --paper-tab-content-focused: {
- /* paper-tabs uses 700 here, which can look awkward */
- font-weight: var(--font-weight-h3);
- }
- --paper-tab-content-unselected: {
- /* paper-tabs uses 0.8 here, but we want to control the color directly */
- opacity: 1;
- color: var(--deemphasized-text-color);
- }
- }
- iron-autogrow-textarea {
- /** This is needed for firefox */
- --iron-autogrow-textarea_-_white-space: pre-wrap;
- }
- strong {
- font-weight: var(--font-weight-bold);
- }
-
- .assistive-tech-only {
- user-select: none;
- clip: rect(1px, 1px, 1px, 1px);
- height: 1px;
- margin: 0;
- overflow: hidden;
- padding: 0;
- position: absolute;
- white-space: nowrap;
- width: 1px;
- z-index: -1000;
- }
-
- /** BEGIN: loading spiner */
- .loadingSpin {
- border: 2px solid var(--disabled-button-background-color);
- border-top: 2px solid var(--primary-button-background-color);
- border-radius: 50%;
- width: 10px;
- height: 10px;
- animation: spin 2s linear infinite;
- margin-right: var(--spacing-s);
- }
- @keyframes spin {
- 0% {
- transform: rotate(0deg);
- }
- 100% {
- transform: rotate(360deg);
- }
- }
- /** END: loading spiner */
-`;
-
$_documentContainer.innerHTML = `<dom-module id="shared-styles">
<template>
<style>
- ${sharedStyles.cssText}
+
+ /* CSS reset */
+
+ html, body, button, div, span, applet, object, iframe, h1, h2, h3,
+ h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite,
+ code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub,
+ sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form,
+ label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article,
+ aside, canvas, details, embed, figure, figcaption, footer, header, hgroup,
+ main, menu, nav, output, ruby, section, summary, time, mark, audio, video {
+ border: 0;
+ box-sizing: border-box;
+ font-size: 100%;
+ font: inherit;
+ margin: 0;
+ padding: 0;
+ vertical-align: baseline;
+ }
+ *::after,
+ *::before {
+ box-sizing: border-box;
+ }
+ input {
+ background-color: var(--background-color-primary);
+ border: 1px solid var(--border-color);
+ border-radius: var(--border-radius);
+ box-sizing: border-box;
+ color: var(--primary-text-color);
+ margin: 0;
+ padding: var(--spacing-s);
+ }
+ iron-autogrow-textarea {
+ background-color: inherit;
+ color: var(--primary-text-color);
+ border: 1px solid var(--border-color);
+ border-radius: var(--border-radius);
+ padding: 0;
+ box-sizing: border-box;
+ /* iron-autogrow-textarea has a "-webkit-appearance: textarea" :host
+ css rule, which prevents overriding the border color. Clear that. */
+ -webkit-appearance: none;
+
+ --iron-autogrow-textarea: {
+ box-sizing: border-box;
+ padding: var(--spacing-s);
+ };
+ }
+ a {
+ color: var(--link-color);
+ }
+ input,
+ textarea,
+ select,
+ button {
+ font: inherit;
+ }
+ ol, ul {
+ list-style: none;
+ }
+ blockquote, q {
+ quotes: none;
+ }
+ blockquote:before, blockquote:after,
+ q:before, q:after {
+ content: '';
+ content: none;
+ }
+ table {
+ border-collapse: collapse;
+ border-spacing: 0;
+ }
+
+ /* Fonts */
+
+ .font-normal {
+ font-size: var(--font-size-normal);
+ font-weight: var(--font-weight-normal);
+ line-height: var(--line-height-normal);
+ }
+ .font-small {
+ font-size: var(--font-size-small);
+ font-weight: var(--font-weight-normal);
+ line-height: var(--line-height-small);
+ }
+ .heading-1 {
+ font-family: var(--header-font-family);
+ font-size: var(--font-size-h1);
+ font-weight: var(--font-weight-h1);
+ line-height: var(--line-height-h1);
+ }
+ .heading-2 {
+ font-family: var(--header-font-family);
+ font-size: var(--font-size-h2);
+ font-weight: var(--font-weight-h2);
+ line-height: var(--line-height-h2);
+ }
+ .heading-3 {
+ font-family: var(--header-font-family);
+ font-size: var(--font-size-h3);
+ font-weight: var(--font-weight-h3);
+ line-height: var(--line-height-h3);
+ }
+ iron-icon {
+ color: var(--deemphasized-text-color);
+ --iron-icon-height: 20px;
+ --iron-icon-width: 20px;
+ }
+
+ /* Stopgap solution until we remove hidden$ attributes. */
+
+ :host([hidden]),
+ [hidden] {
+ display: none !important;
+ }
+ .separator {
+ border-left: 1px solid var(--border-color);
+ height: 20px;
+ margin: 0 8px;
+ }
+ .separator.transparent {
+ border-color: transparent;
+ }
+ paper-toggle-button {
+ --paper-toggle-button-checked-bar-color: var(--link-color);
+ --paper-toggle-button-checked-button-color: var(--link-color);
+ }
+ paper-tabs {
+ font-size: var(--font-size-h3);
+ font-weight: var(--font-weight-h3);
+ line-height: var(--line-height-h3);
+ --paper-font-common-base: {
+ font-family: var(--header-font-family);
+ -webkit-font-smoothing: initial;
+ };
+ --paper-tab-content-focused: {
+ /* paper-tabs uses 700 here, which can look awkward */
+ font-weight: var(--font-weight-h3);
+ };
+ --paper-tab-content-unselected: {
+ /* paper-tabs uses 0.8 here, but we want to control the color directly */
+ opacity: 1;
+ color: var(--deemphasized-text-color);
+ };
+ }
+ iron-autogrow-textarea {
+ /** This is needed for firefox */
+ --iron-autogrow-textarea_-_white-space: pre-wrap;
+ }
+ strong {
+ font-weight: var(--font-weight-bold);
+ }
+
+ .assistive-tech-only {
+ user-select: none;
+ clip: rect(1px, 1px, 1px, 1px);
+ height: 1px;
+ margin: 0;
+ overflow: hidden;
+ padding: 0;
+ position: absolute;
+ white-space: nowrap;
+ width: 1px;
+ z-index: -1000;
+ }
+
+ /** BEGIN: loading spiner */
+ .loadingSpin {
+ border: 2px solid var(--disabled-button-background-color);
+ border-top: 2px solid var(--primary-button-background-color);
+ border-radius: 50%;
+ width: 10px;
+ height: 10px;
+ animation: spin 2s linear infinite;
+ margin-right: var(--spacing-s);
+ }
+ @keyframes spin {
+ 0% { transform: rotate(0deg); }
+ 100% { transform: rotate(360deg); }
+ }
+ /** END: loading spiner */
</style>
</template>
</dom-module>`;