Convert polygerrit to es6-modules

This change replace all HTML imports with es6-modules. The only exceptions are:
* gr-app.html file, which can be deleted only after updating the
  gerrit/httpd/raw/PolyGerritIndexHtml.soy file.
* dark-theme.html which is loaded via importHref. Must be updated manually
  later in a separate change.

This change was produced automatically by ./es6-modules-converter.sh script.
No manual changes were made.

Change-Id: I0c447dd8c05757741e2c940720652d01d9fb7d67
diff --git a/polygerrit-ui/app/elements/shared/gr-comment/gr-comment.js b/polygerrit-ui/app/elements/shared/gr-comment/gr-comment.js
index 9880e88..6f1eaa8 100644
--- a/polygerrit-ui/app/elements/shared/gr-comment/gr-comment.js
+++ b/polygerrit-ui/app/elements/shared/gr-comment/gr-comment.js
@@ -1,6 +1,6 @@
 /**
  * @license
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2015 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.
@@ -14,797 +14,823 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-(function() {
-  'use strict';
+import '../../../scripts/bundled-polymer.js';
 
-  const STORAGE_DEBOUNCE_INTERVAL = 400;
-  const TOAST_DEBOUNCE_INTERVAL = 200;
+import '../../../behaviors/keyboard-shortcut-behavior/keyboard-shortcut-behavior.js';
+import '@polymer/iron-autogrow-textarea/iron-autogrow-textarea.js';
+import '../../../behaviors/fire-behavior/fire-behavior.js';
+import '../../../styles/shared-styles.js';
+import '../../core/gr-reporting/gr-reporting.js';
+import '../../plugins/gr-endpoint-decorator/gr-endpoint-decorator.js';
+import '../../plugins/gr-endpoint-param/gr-endpoint-param.js';
+import '../gr-button/gr-button.js';
+import '../gr-dialog/gr-dialog.js';
+import '../gr-date-formatter/gr-date-formatter.js';
+import '../gr-formatted-text/gr-formatted-text.js';
+import '../gr-icons/gr-icons.js';
+import '../gr-overlay/gr-overlay.js';
+import '../gr-rest-api-interface/gr-rest-api-interface.js';
+import '../gr-storage/gr-storage.js';
+import '../gr-textarea/gr-textarea.js';
+import '../gr-tooltip-content/gr-tooltip-content.js';
+import '../gr-confirm-delete-comment-dialog/gr-confirm-delete-comment-dialog.js';
+import '../../../scripts/rootElement.js';
+import {flush, dom} from '@polymer/polymer/lib/legacy/polymer.dom.js';
+import {mixinBehaviors} from '@polymer/polymer/lib/legacy/class.js';
+import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners.js';
+import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin.js';
+import {PolymerElement} from '@polymer/polymer/polymer-element.js';
+import {htmlTemplate} from './gr-comment_html.js';
 
-  const SAVING_MESSAGE = 'Saving';
-  const DRAFT_SINGULAR = 'draft...';
-  const DRAFT_PLURAL = 'drafts...';
-  const SAVED_MESSAGE = 'All changes saved';
+const STORAGE_DEBOUNCE_INTERVAL = 400;
+const TOAST_DEBOUNCE_INTERVAL = 200;
 
-  const REPORT_CREATE_DRAFT = 'CreateDraftComment';
-  const REPORT_UPDATE_DRAFT = 'UpdateDraftComment';
-  const REPORT_DISCARD_DRAFT = 'DiscardDraftComment';
+const SAVING_MESSAGE = 'Saving';
+const DRAFT_SINGULAR = 'draft...';
+const DRAFT_PLURAL = 'drafts...';
+const SAVED_MESSAGE = 'All changes saved';
 
-  const FILE = 'FILE';
+const REPORT_CREATE_DRAFT = 'CreateDraftComment';
+const REPORT_UPDATE_DRAFT = 'UpdateDraftComment';
+const REPORT_DISCARD_DRAFT = 'DiscardDraftComment';
+
+const FILE = 'FILE';
+
+/**
+ * All candidates tips to show, will pick randomly.
+ */
+const RESPECTFUL_REVIEW_TIPS= [
+  'DO: Assume competence.',
+  'DO: Provide rationale or context.',
+  'DO: Consider how comments may be interpreted.',
+  'DON’T: Criticize the person.',
+  'DON’T: Use harsh language.',
+];
+
+/**
+ * @appliesMixin Gerrit.FireMixin
+ * @appliesMixin Gerrit.KeyboardShortcutMixin
+ * @extends Polymer.Element
+ */
+class GrComment extends mixinBehaviors( [
+  Gerrit.FireBehavior,
+  Gerrit.KeyboardShortcutBehavior,
+], GestureEventListeners(
+    LegacyElementMixin(
+        PolymerElement))) {
+  static get template() { return htmlTemplate; }
+
+  static get is() { return 'gr-comment'; }
+  /**
+   * Fired when the create fix comment action is triggered.
+   *
+   * @event create-fix-comment
+   */
 
   /**
-   * All candidates tips to show, will pick randomly.
+   * Fired when the show fix preview action is triggered.
+   *
+   * @event open-fix-preview
    */
-  const RESPECTFUL_REVIEW_TIPS= [
-    'DO: Assume competence.',
-    'DO: Provide rationale or context.',
-    'DO: Consider how comments may be interpreted.',
-    'DON’T: Criticize the person.',
-    'DON’T: Use harsh language.',
-  ];
 
   /**
-   * @appliesMixin Gerrit.FireMixin
-   * @appliesMixin Gerrit.KeyboardShortcutMixin
-   * @extends Polymer.Element
+   * Fired when this comment is discarded.
+   *
+   * @event comment-discard
    */
-  class GrComment extends Polymer.mixinBehaviors( [
-    Gerrit.FireBehavior,
-    Gerrit.KeyboardShortcutBehavior,
-  ], Polymer.GestureEventListeners(
-      Polymer.LegacyElementMixin(
-          Polymer.Element))) {
-    static get is() { return 'gr-comment'; }
-    /**
-     * Fired when the create fix comment action is triggered.
-     *
-     * @event create-fix-comment
-     */
 
-    /**
-     * Fired when the show fix preview action is triggered.
-     *
-     * @event open-fix-preview
-     */
+  /**
+   * Fired when this comment is saved.
+   *
+   * @event comment-save
+   */
 
-    /**
-     * Fired when this comment is discarded.
-     *
-     * @event comment-discard
-     */
+  /**
+   * Fired when this comment is updated.
+   *
+   * @event comment-update
+   */
 
-    /**
-     * Fired when this comment is saved.
-     *
-     * @event comment-save
-     */
+  /**
+   * Fired when the comment's timestamp is tapped.
+   *
+   * @event comment-anchor-tap
+   */
 
-    /**
-     * Fired when this comment is updated.
-     *
-     * @event comment-update
-     */
+  static get properties() {
+    return {
+      changeNum: String,
+      /** @type {!Gerrit.Comment} */
+      comment: {
+        type: Object,
+        notify: true,
+        observer: '_commentChanged',
+      },
+      comments: {
+        type: Array,
+      },
+      isRobotComment: {
+        type: Boolean,
+        value: false,
+        reflectToAttribute: true,
+      },
+      disabled: {
+        type: Boolean,
+        value: false,
+        reflectToAttribute: true,
+      },
+      draft: {
+        type: Boolean,
+        value: false,
+        observer: '_draftChanged',
+      },
+      editing: {
+        type: Boolean,
+        value: false,
+        observer: '_editingChanged',
+      },
+      discarding: {
+        type: Boolean,
+        value: false,
+        reflectToAttribute: true,
+      },
+      hasChildren: Boolean,
+      patchNum: String,
+      showActions: Boolean,
+      _showHumanActions: Boolean,
+      _showRobotActions: Boolean,
+      collapsed: {
+        type: Boolean,
+        value: true,
+        observer: '_toggleCollapseClass',
+      },
+      /** @type {?} */
+      projectConfig: Object,
+      robotButtonDisabled: Boolean,
+      _hasHumanReply: Boolean,
+      _isAdmin: {
+        type: Boolean,
+        value: false,
+      },
 
-    /**
-     * Fired when the comment's timestamp is tapped.
-     *
-     * @event comment-anchor-tap
-     */
+      _xhrPromise: Object, // Used for testing.
+      _messageText: {
+        type: String,
+        value: '',
+        observer: '_messageTextChanged',
+      },
+      commentSide: String,
+      side: String,
 
-    static get properties() {
-      return {
-        changeNum: String,
-        /** @type {!Gerrit.Comment} */
-        comment: {
-          type: Object,
-          notify: true,
-          observer: '_commentChanged',
-        },
-        comments: {
-          type: Array,
-        },
-        isRobotComment: {
-          type: Boolean,
-          value: false,
-          reflectToAttribute: true,
-        },
-        disabled: {
-          type: Boolean,
-          value: false,
-          reflectToAttribute: true,
-        },
-        draft: {
-          type: Boolean,
-          value: false,
-          observer: '_draftChanged',
-        },
-        editing: {
-          type: Boolean,
-          value: false,
-          observer: '_editingChanged',
-        },
-        discarding: {
-          type: Boolean,
-          value: false,
-          reflectToAttribute: true,
-        },
-        hasChildren: Boolean,
-        patchNum: String,
-        showActions: Boolean,
-        _showHumanActions: Boolean,
-        _showRobotActions: Boolean,
-        collapsed: {
-          type: Boolean,
-          value: true,
-          observer: '_toggleCollapseClass',
-        },
-        /** @type {?} */
-        projectConfig: Object,
-        robotButtonDisabled: Boolean,
-        _hasHumanReply: Boolean,
-        _isAdmin: {
-          type: Boolean,
-          value: false,
-        },
+      resolved: Boolean,
 
-        _xhrPromise: Object, // Used for testing.
-        _messageText: {
-          type: String,
-          value: '',
-          observer: '_messageTextChanged',
-        },
-        commentSide: String,
-        side: String,
+      _numPendingDraftRequests: {
+        type: Object,
+        value:
+          {number: 0}, // Intentional to share the object across instances.
+      },
 
-        resolved: Boolean,
+      _enableOverlay: {
+        type: Boolean,
+        value: false,
+      },
 
-        _numPendingDraftRequests: {
-          type: Object,
-          value:
-            {number: 0}, // Intentional to share the object across instances.
-        },
+      /**
+       * Property for storing references to overlay elements. When the overlays
+       * are moved to Gerrit.getRootElement() to be shown they are no-longer
+       * children, so they can't be queried along the tree, so they are stored
+       * here.
+       */
+      _overlays: {
+        type: Object,
+        value: () => { return {}; },
+      },
 
-        _enableOverlay: {
-          type: Boolean,
-          value: false,
-        },
+      _showRespectfulTip: {
+        type: Boolean,
+        value: false,
+      },
+      _respectfulReviewTip: String,
+      _respectfulTipDismissed: {
+        type: Boolean,
+        value: false,
+      },
+    };
+  }
 
-        /**
-         * Property for storing references to overlay elements. When the overlays
-         * are moved to Gerrit.getRootElement() to be shown they are no-longer
-         * children, so they can't be queried along the tree, so they are stored
-         * here.
-         */
-        _overlays: {
-          type: Object,
-          value: () => { return {}; },
-        },
+  static get observers() {
+    return [
+      '_commentMessageChanged(comment.message)',
+      '_loadLocalDraft(changeNum, patchNum, comment)',
+      '_isRobotComment(comment)',
+      '_calculateActionstoShow(showActions, isRobotComment)',
+      '_computeHasHumanReply(comment, comments.*)',
+      '_onEditingChange(editing)',
+    ];
+  }
 
-        _showRespectfulTip: {
-          type: Boolean,
-          value: false,
-        },
-        _respectfulReviewTip: String,
-        _respectfulTipDismissed: {
-          type: Boolean,
-          value: false,
-        },
-      };
+  get keyBindings() {
+    return {
+      'ctrl+enter meta+enter ctrl+s meta+s': '_handleSaveKey',
+      'esc': '_handleEsc',
+    };
+  }
+
+  /** @override */
+  attached() {
+    super.attached();
+    if (this.editing) {
+      this.collapsed = false;
+    } else if (this.comment) {
+      this.collapsed = this.comment.collapsed;
     }
+    this._getIsAdmin().then(isAdmin => {
+      this._isAdmin = isAdmin;
+    });
+  }
 
-    static get observers() {
-      return [
-        '_commentMessageChanged(comment.message)',
-        '_loadLocalDraft(changeNum, patchNum, comment)',
-        '_isRobotComment(comment)',
-        '_calculateActionstoShow(showActions, isRobotComment)',
-        '_computeHasHumanReply(comment, comments.*)',
-        '_onEditingChange(editing)',
-      ];
+  /** @override */
+  detached() {
+    super.detached();
+    this.cancelDebouncer('fire-update');
+    if (this.textarea) {
+      this.textarea.closeDropdown();
     }
+  }
 
-    get keyBindings() {
-      return {
-        'ctrl+enter meta+enter ctrl+s meta+s': '_handleSaveKey',
-        'esc': '_handleEsc',
-      };
-    }
-
-    /** @override */
-    attached() {
-      super.attached();
-      if (this.editing) {
-        this.collapsed = false;
-      } else if (this.comment) {
-        this.collapsed = this.comment.collapsed;
-      }
-      this._getIsAdmin().then(isAdmin => {
-        this._isAdmin = isAdmin;
-      });
-    }
-
-    /** @override */
-    detached() {
-      super.detached();
-      this.cancelDebouncer('fire-update');
-      if (this.textarea) {
-        this.textarea.closeDropdown();
-      }
-    }
-
-    _onEditingChange(editing) {
-      if (!editing) return;
-      // visibility based on cache this will make sure we only and always show
-      // a tip once every Math.max(a day, period between creating comments)
-      const cachedVisibilityOfRespectfulTip =
-        this.$.storage.getRespectfulTipVisibility();
-      if (!cachedVisibilityOfRespectfulTip) {
-        // we still want to show the tip with a probability of 30%
-        if (this.getRandomNum(0, 3) >= 1) return;
-        this._showRespectfulTip = true;
-        const randomIdx = this.getRandomNum(0, RESPECTFUL_REVIEW_TIPS.length);
-        this._respectfulReviewTip = RESPECTFUL_REVIEW_TIPS[randomIdx];
-        this.$.reporting.reportInteraction(
-            'respectful-tip-appeared',
-            {tip: this._respectfulReviewTip}
-        );
-        // update cache
-        this.$.storage.setRespectfulTipVisibility();
-      }
-    }
-
-    /** Set as a separate method so easy to stub. */
-    getRandomNum(min, max) {
-      return Math.floor(Math.random() * (max - min) + min);
-    }
-
-    _computeVisibilityOfTip(showTip, tipDismissed) {
-      return showTip && !tipDismissed;
-    }
-
-    _dismissRespectfulTip() {
-      this._respectfulTipDismissed = true;
+  _onEditingChange(editing) {
+    if (!editing) return;
+    // visibility based on cache this will make sure we only and always show
+    // a tip once every Math.max(a day, period between creating comments)
+    const cachedVisibilityOfRespectfulTip =
+      this.$.storage.getRespectfulTipVisibility();
+    if (!cachedVisibilityOfRespectfulTip) {
+      // we still want to show the tip with a probability of 30%
+      if (this.getRandomNum(0, 3) >= 1) return;
+      this._showRespectfulTip = true;
+      const randomIdx = this.getRandomNum(0, RESPECTFUL_REVIEW_TIPS.length);
+      this._respectfulReviewTip = RESPECTFUL_REVIEW_TIPS[randomIdx];
       this.$.reporting.reportInteraction(
-          'respectful-tip-dismissed',
+          'respectful-tip-appeared',
           {tip: this._respectfulReviewTip}
       );
-      // add a 3 day delay to the tip cache
-      this.$.storage.setRespectfulTipVisibility(/* delayDays= */ 3);
+      // update cache
+      this.$.storage.setRespectfulTipVisibility();
+    }
+  }
+
+  /** Set as a separate method so easy to stub. */
+  getRandomNum(min, max) {
+    return Math.floor(Math.random() * (max - min) + min);
+  }
+
+  _computeVisibilityOfTip(showTip, tipDismissed) {
+    return showTip && !tipDismissed;
+  }
+
+  _dismissRespectfulTip() {
+    this._respectfulTipDismissed = true;
+    this.$.reporting.reportInteraction(
+        'respectful-tip-dismissed',
+        {tip: this._respectfulReviewTip}
+    );
+    // add a 3 day delay to the tip cache
+    this.$.storage.setRespectfulTipVisibility(/* delayDays= */ 3);
+  }
+
+  _onRespectfulReadMoreClick() {
+    this.$.reporting.reportInteraction('respectful-read-more-clicked');
+  }
+
+  get textarea() {
+    return this.shadowRoot.querySelector('#editTextarea');
+  }
+
+  get confirmDeleteOverlay() {
+    if (!this._overlays.confirmDelete) {
+      this._enableOverlay = true;
+      flush();
+      this._overlays.confirmDelete = this.shadowRoot
+          .querySelector('#confirmDeleteOverlay');
+    }
+    return this._overlays.confirmDelete;
+  }
+
+  get confirmDiscardOverlay() {
+    if (!this._overlays.confirmDiscard) {
+      this._enableOverlay = true;
+      flush();
+      this._overlays.confirmDiscard = this.shadowRoot
+          .querySelector('#confirmDiscardOverlay');
+    }
+    return this._overlays.confirmDiscard;
+  }
+
+  _computeShowHideIcon(collapsed) {
+    return collapsed ? 'gr-icons:expand-more' : 'gr-icons:expand-less';
+  }
+
+  _calculateActionstoShow(showActions, isRobotComment) {
+    // Polymer 2: check for undefined
+    if ([showActions, isRobotComment].some(arg => arg === undefined)) {
+      return;
     }
 
-    _onRespectfulReadMoreClick() {
-      this.$.reporting.reportInteraction('respectful-read-more-clicked');
+    this._showHumanActions = showActions && !isRobotComment;
+    this._showRobotActions = showActions && isRobotComment;
+  }
+
+  _isRobotComment(comment) {
+    this.isRobotComment = !!comment.robot_id;
+  }
+
+  isOnParent() {
+    return this.side === 'PARENT';
+  }
+
+  _getIsAdmin() {
+    return this.$.restAPI.getIsAdmin();
+  }
+
+  /**
+   * @param {*=} opt_comment
+   */
+  save(opt_comment) {
+    let comment = opt_comment;
+    if (!comment) {
+      comment = this.comment;
     }
 
-    get textarea() {
-      return this.shadowRoot.querySelector('#editTextarea');
+    this.set('comment.message', this._messageText);
+    this.editing = false;
+    this.disabled = true;
+
+    if (!this._messageText) {
+      return this._discardDraft();
     }
 
-    get confirmDeleteOverlay() {
-      if (!this._overlays.confirmDelete) {
-        this._enableOverlay = true;
-        Polymer.dom.flush();
-        this._overlays.confirmDelete = this.shadowRoot
-            .querySelector('#confirmDeleteOverlay');
-      }
-      return this._overlays.confirmDelete;
-    }
+    this._xhrPromise = this._saveDraft(comment).then(response => {
+      this.disabled = false;
+      if (!response.ok) { return response; }
 
-    get confirmDiscardOverlay() {
-      if (!this._overlays.confirmDiscard) {
-        this._enableOverlay = true;
-        Polymer.dom.flush();
-        this._overlays.confirmDiscard = this.shadowRoot
-            .querySelector('#confirmDiscardOverlay');
-      }
-      return this._overlays.confirmDiscard;
-    }
-
-    _computeShowHideIcon(collapsed) {
-      return collapsed ? 'gr-icons:expand-more' : 'gr-icons:expand-less';
-    }
-
-    _calculateActionstoShow(showActions, isRobotComment) {
-      // Polymer 2: check for undefined
-      if ([showActions, isRobotComment].some(arg => arg === undefined)) {
-        return;
-      }
-
-      this._showHumanActions = showActions && !isRobotComment;
-      this._showRobotActions = showActions && isRobotComment;
-    }
-
-    _isRobotComment(comment) {
-      this.isRobotComment = !!comment.robot_id;
-    }
-
-    isOnParent() {
-      return this.side === 'PARENT';
-    }
-
-    _getIsAdmin() {
-      return this.$.restAPI.getIsAdmin();
-    }
-
-    /**
-     * @param {*=} opt_comment
-     */
-    save(opt_comment) {
-      let comment = opt_comment;
-      if (!comment) {
-        comment = this.comment;
-      }
-
-      this.set('comment.message', this._messageText);
-      this.editing = false;
-      this.disabled = true;
-
-      if (!this._messageText) {
-        return this._discardDraft();
-      }
-
-      this._xhrPromise = this._saveDraft(comment).then(response => {
-        this.disabled = false;
-        if (!response.ok) { return response; }
-
-        this._eraseDraftComment();
-        return this.$.restAPI.getResponseObject(response).then(obj => {
-          const resComment = obj;
-          resComment.__draft = true;
-          // Maintain the ephemeral draft ID for identification by other
-          // elements.
-          if (this.comment.__draftID) {
-            resComment.__draftID = this.comment.__draftID;
-          }
-          resComment.__commentSide = this.commentSide;
-          this.comment = resComment;
-          this._fireSave();
-          return obj;
+      this._eraseDraftComment();
+      return this.$.restAPI.getResponseObject(response).then(obj => {
+        const resComment = obj;
+        resComment.__draft = true;
+        // Maintain the ephemeral draft ID for identification by other
+        // elements.
+        if (this.comment.__draftID) {
+          resComment.__draftID = this.comment.__draftID;
+        }
+        resComment.__commentSide = this.commentSide;
+        this.comment = resComment;
+        this._fireSave();
+        return obj;
+      });
+    })
+        .catch(err => {
+          this.disabled = false;
+          throw err;
         });
-      })
-          .catch(err => {
-            this.disabled = false;
-            throw err;
-          });
 
-      return this._xhrPromise;
+    return this._xhrPromise;
+  }
+
+  _eraseDraftComment() {
+    // Prevents a race condition in which removing the draft comment occurs
+    // prior to it being saved.
+    this.cancelDebouncer('store');
+
+    this.$.storage.eraseDraftComment({
+      changeNum: this.changeNum,
+      patchNum: this._getPatchNum(),
+      path: this.comment.path,
+      line: this.comment.line,
+      range: this.comment.range,
+    });
+  }
+
+  _commentChanged(comment) {
+    this.editing = !!comment.__editing;
+    this.resolved = !comment.unresolved;
+    if (this.editing) { // It's a new draft/reply, notify.
+      this._fireUpdate();
+    }
+  }
+
+  _computeHasHumanReply() {
+    if (!this.comment || !this.comments) return;
+    // hide please fix button for robot comment that has human reply
+    this._hasHumanReply = this.comments
+        .some(c => c.in_reply_to && c.in_reply_to === this.comment.id &&
+          !c.robot_id);
+  }
+
+  /**
+   * @param {!Object=} opt_mixin
+   *
+   * @return {!Object}
+   */
+  _getEventPayload(opt_mixin) {
+    return Object.assign({}, opt_mixin, {
+      comment: this.comment,
+      patchNum: this.patchNum,
+    });
+  }
+
+  _fireSave() {
+    this.fire('comment-save', this._getEventPayload());
+  }
+
+  _fireUpdate() {
+    this.debounce('fire-update', () => {
+      this.fire('comment-update', this._getEventPayload());
+    });
+  }
+
+  _draftChanged(draft) {
+    this.$.container.classList.toggle('draft', draft);
+  }
+
+  _editingChanged(editing, previousValue) {
+    // Polymer 2: observer fires when at least one property is defined.
+    // Do nothing to prevent comment.__editing being overwritten
+    // if previousValue is undefined
+    if (previousValue === undefined) return;
+
+    this.$.container.classList.toggle('editing', editing);
+    if (this.comment && this.comment.id) {
+      this.shadowRoot.querySelector('.cancel').hidden = !editing;
+    }
+    if (this.comment) {
+      this.comment.__editing = this.editing;
+    }
+    if (editing != !!previousValue) {
+      // To prevent event firing on comment creation.
+      this._fireUpdate();
+    }
+    if (editing) {
+      this.async(() => {
+        flush();
+        this.textarea && this.textarea.putCursorAtEnd();
+      }, 1);
+    }
+  }
+
+  _computeDeleteButtonClass(isAdmin, draft) {
+    return isAdmin && !draft ? 'showDeleteButtons' : '';
+  }
+
+  _computeSaveDisabled(draft, comment, resolved) {
+    // If resolved state has changed and a msg exists, save should be enabled.
+    if (!comment || comment.unresolved === resolved && draft) {
+      return false;
+    }
+    return !draft || draft.trim() === '';
+  }
+
+  _handleSaveKey(e) {
+    if (!this._computeSaveDisabled(this._messageText, this.comment,
+        this.resolved)) {
+      e.preventDefault();
+      this._handleSave(e);
+    }
+  }
+
+  _handleEsc(e) {
+    if (!this._messageText.length) {
+      e.preventDefault();
+      this._handleCancel(e);
+    }
+  }
+
+  _handleToggleCollapsed() {
+    this.collapsed = !this.collapsed;
+  }
+
+  _toggleCollapseClass(collapsed) {
+    if (collapsed) {
+      this.$.container.classList.add('collapsed');
+    } else {
+      this.$.container.classList.remove('collapsed');
+    }
+  }
+
+  _commentMessageChanged(message) {
+    this._messageText = message || '';
+  }
+
+  _messageTextChanged(newValue, oldValue) {
+    if (!this.comment || (this.comment && this.comment.id)) {
+      return;
     }
 
-    _eraseDraftComment() {
-      // Prevents a race condition in which removing the draft comment occurs
-      // prior to it being saved.
-      this.cancelDebouncer('store');
-
-      this.$.storage.eraseDraftComment({
+    this.debounce('store', () => {
+      const message = this._messageText;
+      const commentLocation = {
         changeNum: this.changeNum,
         patchNum: this._getPatchNum(),
         path: this.comment.path,
         line: this.comment.line,
         range: this.comment.range,
-      });
-    }
+      };
 
-    _commentChanged(comment) {
-      this.editing = !!comment.__editing;
-      this.resolved = !comment.unresolved;
-      if (this.editing) { // It's a new draft/reply, notify.
-        this._fireUpdate();
-      }
-    }
-
-    _computeHasHumanReply() {
-      if (!this.comment || !this.comments) return;
-      // hide please fix button for robot comment that has human reply
-      this._hasHumanReply = this.comments
-          .some(c => c.in_reply_to && c.in_reply_to === this.comment.id &&
-            !c.robot_id);
-    }
-
-    /**
-     * @param {!Object=} opt_mixin
-     *
-     * @return {!Object}
-     */
-    _getEventPayload(opt_mixin) {
-      return Object.assign({}, opt_mixin, {
-        comment: this.comment,
-        patchNum: this.patchNum,
-      });
-    }
-
-    _fireSave() {
-      this.fire('comment-save', this._getEventPayload());
-    }
-
-    _fireUpdate() {
-      this.debounce('fire-update', () => {
-        this.fire('comment-update', this._getEventPayload());
-      });
-    }
-
-    _draftChanged(draft) {
-      this.$.container.classList.toggle('draft', draft);
-    }
-
-    _editingChanged(editing, previousValue) {
-      // Polymer 2: observer fires when at least one property is defined.
-      // Do nothing to prevent comment.__editing being overwritten
-      // if previousValue is undefined
-      if (previousValue === undefined) return;
-
-      this.$.container.classList.toggle('editing', editing);
-      if (this.comment && this.comment.id) {
-        this.shadowRoot.querySelector('.cancel').hidden = !editing;
-      }
-      if (this.comment) {
-        this.comment.__editing = this.editing;
-      }
-      if (editing != !!previousValue) {
-        // To prevent event firing on comment creation.
-        this._fireUpdate();
-      }
-      if (editing) {
-        this.async(() => {
-          Polymer.dom.flush();
-          this.textarea && this.textarea.putCursorAtEnd();
-        }, 1);
-      }
-    }
-
-    _computeDeleteButtonClass(isAdmin, draft) {
-      return isAdmin && !draft ? 'showDeleteButtons' : '';
-    }
-
-    _computeSaveDisabled(draft, comment, resolved) {
-      // If resolved state has changed and a msg exists, save should be enabled.
-      if (!comment || comment.unresolved === resolved && draft) {
-        return false;
-      }
-      return !draft || draft.trim() === '';
-    }
-
-    _handleSaveKey(e) {
-      if (!this._computeSaveDisabled(this._messageText, this.comment,
-          this.resolved)) {
-        e.preventDefault();
-        this._handleSave(e);
-      }
-    }
-
-    _handleEsc(e) {
-      if (!this._messageText.length) {
-        e.preventDefault();
-        this._handleCancel(e);
-      }
-    }
-
-    _handleToggleCollapsed() {
-      this.collapsed = !this.collapsed;
-    }
-
-    _toggleCollapseClass(collapsed) {
-      if (collapsed) {
-        this.$.container.classList.add('collapsed');
+      if ((!this._messageText || !this._messageText.length) && oldValue) {
+        // If the draft has been modified to be empty, then erase the storage
+        // entry.
+        this.$.storage.eraseDraftComment(commentLocation);
       } else {
-        this.$.container.classList.remove('collapsed');
+        this.$.storage.setDraftComment(commentLocation, message);
       }
+    }, STORAGE_DEBOUNCE_INTERVAL);
+  }
+
+  _handleAnchorClick(e) {
+    e.preventDefault();
+    if (!this.comment.line) {
+      return;
+    }
+    this.dispatchEvent(new CustomEvent('comment-anchor-tap', {
+      bubbles: true,
+      composed: true,
+      detail: {
+        number: this.comment.line || FILE,
+        side: this.side,
+      },
+    }));
+  }
+
+  _handleEdit(e) {
+    e.preventDefault();
+    this._messageText = this.comment.message;
+    this.editing = true;
+    this.$.reporting.recordDraftInteraction();
+  }
+
+  _handleSave(e) {
+    e.preventDefault();
+
+    // Ignore saves started while already saving.
+    if (this.disabled) {
+      return;
+    }
+    const timingLabel = this.comment.id ?
+      REPORT_UPDATE_DRAFT : REPORT_CREATE_DRAFT;
+    const timer = this.$.reporting.getTimer(timingLabel);
+    this.set('comment.__editing', false);
+    return this.save().then(() => { timer.end(); });
+  }
+
+  _handleCancel(e) {
+    e.preventDefault();
+
+    if (!this.comment.message ||
+        this.comment.message.trim().length === 0 ||
+        !this.comment.id) {
+      this._fireDiscard();
+      return;
+    }
+    this._messageText = this.comment.message;
+    this.editing = false;
+  }
+
+  _fireDiscard() {
+    this.cancelDebouncer('fire-update');
+    this.fire('comment-discard', this._getEventPayload());
+  }
+
+  _handleFix() {
+    this.dispatchEvent(new CustomEvent('create-fix-comment', {
+      bubbles: true,
+      composed: true,
+      detail: this._getEventPayload(),
+    }));
+  }
+
+  _handleShowFix() {
+    this.dispatchEvent(new CustomEvent('open-fix-preview', {
+      bubbles: true,
+      composed: true,
+      detail: this._getEventPayload(),
+    }));
+  }
+
+  _hasNoFix(comment) {
+    return !comment || !comment.fix_suggestions;
+  }
+
+  _handleDiscard(e) {
+    e.preventDefault();
+    this.$.reporting.recordDraftInteraction();
+
+    if (!this._messageText) {
+      this._discardDraft();
+      return;
     }
 
-    _commentMessageChanged(message) {
-      this._messageText = message || '';
+    this._openOverlay(this.confirmDiscardOverlay).then(() => {
+      this.confirmDiscardOverlay.querySelector('#confirmDiscardDialog')
+          .resetFocus();
+    });
+  }
+
+  _handleConfirmDiscard(e) {
+    e.preventDefault();
+    const timer = this.$.reporting.getTimer(REPORT_DISCARD_DRAFT);
+    this._closeConfirmDiscardOverlay();
+    return this._discardDraft().then(() => { timer.end(); });
+  }
+
+  _discardDraft() {
+    if (!this.comment.__draft) {
+      throw Error('Cannot discard a non-draft comment.');
+    }
+    this.discarding = true;
+    this.editing = false;
+    this.disabled = true;
+    this._eraseDraftComment();
+
+    if (!this.comment.id) {
+      this.disabled = false;
+      this._fireDiscard();
+      return;
     }
 
-    _messageTextChanged(newValue, oldValue) {
-      if (!this.comment || (this.comment && this.comment.id)) {
-        return;
+    this._xhrPromise = this._deleteDraft(this.comment).then(response => {
+      this.disabled = false;
+      if (!response.ok) {
+        this.discarding = false;
+        return response;
       }
 
-      this.debounce('store', () => {
-        const message = this._messageText;
-        const commentLocation = {
-          changeNum: this.changeNum,
-          patchNum: this._getPatchNum(),
-          path: this.comment.path,
-          line: this.comment.line,
-          range: this.comment.range,
-        };
+      this._fireDiscard();
+    })
+        .catch(err => {
+          this.disabled = false;
+          throw err;
+        });
 
-        if ((!this._messageText || !this._messageText.length) && oldValue) {
-          // If the draft has been modified to be empty, then erase the storage
-          // entry.
-          this.$.storage.eraseDraftComment(commentLocation);
-        } else {
-          this.$.storage.setDraftComment(commentLocation, message);
-        }
-      }, STORAGE_DEBOUNCE_INTERVAL);
+    return this._xhrPromise;
+  }
+
+  _closeConfirmDiscardOverlay() {
+    this._closeOverlay(this.confirmDiscardOverlay);
+  }
+
+  _getSavingMessage(numPending) {
+    if (numPending === 0) {
+      return SAVED_MESSAGE;
     }
+    return [
+      SAVING_MESSAGE,
+      numPending,
+      numPending === 1 ? DRAFT_SINGULAR : DRAFT_PLURAL,
+    ].join(' ');
+  }
 
-    _handleAnchorClick(e) {
-      e.preventDefault();
-      if (!this.comment.line) {
-        return;
+  _showStartRequest() {
+    const numPending = ++this._numPendingDraftRequests.number;
+    this._updateRequestToast(numPending);
+  }
+
+  _showEndRequest() {
+    const numPending = --this._numPendingDraftRequests.number;
+    this._updateRequestToast(numPending);
+  }
+
+  _handleFailedDraftRequest() {
+    this._numPendingDraftRequests.number--;
+
+    // Cancel the debouncer so that error toasts from the error-manager will
+    // not be overridden.
+    this.cancelDebouncer('draft-toast');
+  }
+
+  _updateRequestToast(numPending) {
+    const message = this._getSavingMessage(numPending);
+    this.debounce('draft-toast', () => {
+      // Note: the event is fired on the body rather than this element because
+      // this element may not be attached by the time this executes, in which
+      // case the event would not bubble.
+      document.body.dispatchEvent(new CustomEvent(
+          'show-alert', {detail: {message}, bubbles: true, composed: true}));
+    }, TOAST_DEBOUNCE_INTERVAL);
+  }
+
+  _saveDraft(draft) {
+    this._showStartRequest();
+    return this.$.restAPI.saveDiffDraft(this.changeNum, this.patchNum, draft)
+        .then(result => {
+          if (result.ok) {
+            this._showEndRequest();
+          } else {
+            this._handleFailedDraftRequest();
+          }
+          return result;
+        });
+  }
+
+  _deleteDraft(draft) {
+    this._showStartRequest();
+    return this.$.restAPI.deleteDiffDraft(this.changeNum, this.patchNum,
+        draft).then(result => {
+      if (result.ok) {
+        this._showEndRequest();
+      } else {
+        this._handleFailedDraftRequest();
       }
-      this.dispatchEvent(new CustomEvent('comment-anchor-tap', {
-        bubbles: true,
-        composed: true,
-        detail: {
-          number: this.comment.line || FILE,
-          side: this.side,
-        },
-      }));
+      return result;
+    });
+  }
+
+  _getPatchNum() {
+    return this.isOnParent() ? 'PARENT' : this.patchNum;
+  }
+
+  _loadLocalDraft(changeNum, patchNum, comment) {
+    // Polymer 2: check for undefined
+    if ([changeNum, patchNum, comment].some(arg => arg === undefined)) {
+      return;
     }
 
-    _handleEdit(e) {
-      e.preventDefault();
-      this._messageText = this.comment.message;
-      this.editing = true;
-      this.$.reporting.recordDraftInteraction();
+    // Only apply local drafts to comments that haven't been saved
+    // remotely, and haven't been given a default message already.
+    //
+    // Don't get local draft if there is another comment that is currently
+    // in an editing state.
+    if (!comment || comment.id || comment.message || comment.__otherEditing) {
+      delete comment.__otherEditing;
+      return;
     }
 
-    _handleSave(e) {
-      e.preventDefault();
+    const draft = this.$.storage.getDraftComment({
+      changeNum,
+      patchNum: this._getPatchNum(),
+      path: comment.path,
+      line: comment.line,
+      range: comment.range,
+    });
 
-      // Ignore saves started while already saving.
-      if (this.disabled) {
-        return;
-      }
-      const timingLabel = this.comment.id ?
-        REPORT_UPDATE_DRAFT : REPORT_CREATE_DRAFT;
-      const timer = this.$.reporting.getTimer(timingLabel);
-      this.set('comment.__editing', false);
-      return this.save().then(() => { timer.end(); });
-    }
-
-    _handleCancel(e) {
-      e.preventDefault();
-
-      if (!this.comment.message ||
-          this.comment.message.trim().length === 0 ||
-          !this.comment.id) {
-        this._fireDiscard();
-        return;
-      }
-      this._messageText = this.comment.message;
-      this.editing = false;
-    }
-
-    _fireDiscard() {
-      this.cancelDebouncer('fire-update');
-      this.fire('comment-discard', this._getEventPayload());
-    }
-
-    _handleFix() {
-      this.dispatchEvent(new CustomEvent('create-fix-comment', {
-        bubbles: true,
-        composed: true,
-        detail: this._getEventPayload(),
-      }));
-    }
-
-    _handleShowFix() {
-      this.dispatchEvent(new CustomEvent('open-fix-preview', {
-        bubbles: true,
-        composed: true,
-        detail: this._getEventPayload(),
-      }));
-    }
-
-    _hasNoFix(comment) {
-      return !comment || !comment.fix_suggestions;
-    }
-
-    _handleDiscard(e) {
-      e.preventDefault();
-      this.$.reporting.recordDraftInteraction();
-
-      if (!this._messageText) {
-        this._discardDraft();
-        return;
-      }
-
-      this._openOverlay(this.confirmDiscardOverlay).then(() => {
-        this.confirmDiscardOverlay.querySelector('#confirmDiscardDialog')
-            .resetFocus();
-      });
-    }
-
-    _handleConfirmDiscard(e) {
-      e.preventDefault();
-      const timer = this.$.reporting.getTimer(REPORT_DISCARD_DRAFT);
-      this._closeConfirmDiscardOverlay();
-      return this._discardDraft().then(() => { timer.end(); });
-    }
-
-    _discardDraft() {
-      if (!this.comment.__draft) {
-        throw Error('Cannot discard a non-draft comment.');
-      }
-      this.discarding = true;
-      this.editing = false;
-      this.disabled = true;
-      this._eraseDraftComment();
-
-      if (!this.comment.id) {
-        this.disabled = false;
-        this._fireDiscard();
-        return;
-      }
-
-      this._xhrPromise = this._deleteDraft(this.comment).then(response => {
-        this.disabled = false;
-        if (!response.ok) {
-          this.discarding = false;
-          return response;
-        }
-
-        this._fireDiscard();
-      })
-          .catch(err => {
-            this.disabled = false;
-            throw err;
-          });
-
-      return this._xhrPromise;
-    }
-
-    _closeConfirmDiscardOverlay() {
-      this._closeOverlay(this.confirmDiscardOverlay);
-    }
-
-    _getSavingMessage(numPending) {
-      if (numPending === 0) {
-        return SAVED_MESSAGE;
-      }
-      return [
-        SAVING_MESSAGE,
-        numPending,
-        numPending === 1 ? DRAFT_SINGULAR : DRAFT_PLURAL,
-      ].join(' ');
-    }
-
-    _showStartRequest() {
-      const numPending = ++this._numPendingDraftRequests.number;
-      this._updateRequestToast(numPending);
-    }
-
-    _showEndRequest() {
-      const numPending = --this._numPendingDraftRequests.number;
-      this._updateRequestToast(numPending);
-    }
-
-    _handleFailedDraftRequest() {
-      this._numPendingDraftRequests.number--;
-
-      // Cancel the debouncer so that error toasts from the error-manager will
-      // not be overridden.
-      this.cancelDebouncer('draft-toast');
-    }
-
-    _updateRequestToast(numPending) {
-      const message = this._getSavingMessage(numPending);
-      this.debounce('draft-toast', () => {
-        // Note: the event is fired on the body rather than this element because
-        // this element may not be attached by the time this executes, in which
-        // case the event would not bubble.
-        document.body.dispatchEvent(new CustomEvent(
-            'show-alert', {detail: {message}, bubbles: true, composed: true}));
-      }, TOAST_DEBOUNCE_INTERVAL);
-    }
-
-    _saveDraft(draft) {
-      this._showStartRequest();
-      return this.$.restAPI.saveDiffDraft(this.changeNum, this.patchNum, draft)
-          .then(result => {
-            if (result.ok) {
-              this._showEndRequest();
-            } else {
-              this._handleFailedDraftRequest();
-            }
-            return result;
-          });
-    }
-
-    _deleteDraft(draft) {
-      this._showStartRequest();
-      return this.$.restAPI.deleteDiffDraft(this.changeNum, this.patchNum,
-          draft).then(result => {
-        if (result.ok) {
-          this._showEndRequest();
-        } else {
-          this._handleFailedDraftRequest();
-        }
-        return result;
-      });
-    }
-
-    _getPatchNum() {
-      return this.isOnParent() ? 'PARENT' : this.patchNum;
-    }
-
-    _loadLocalDraft(changeNum, patchNum, comment) {
-      // Polymer 2: check for undefined
-      if ([changeNum, patchNum, comment].some(arg => arg === undefined)) {
-        return;
-      }
-
-      // Only apply local drafts to comments that haven't been saved
-      // remotely, and haven't been given a default message already.
-      //
-      // Don't get local draft if there is another comment that is currently
-      // in an editing state.
-      if (!comment || comment.id || comment.message || comment.__otherEditing) {
-        delete comment.__otherEditing;
-        return;
-      }
-
-      const draft = this.$.storage.getDraftComment({
-        changeNum,
-        patchNum: this._getPatchNum(),
-        path: comment.path,
-        line: comment.line,
-        range: comment.range,
-      });
-
-      if (draft) {
-        this.set('comment.message', draft.message);
-      }
-    }
-
-    _handleToggleResolved() {
-      this.$.reporting.recordDraftInteraction();
-      this.resolved = !this.resolved;
-      // Modify payload instead of this.comment, as this.comment is passed from
-      // the parent by ref.
-      const payload = this._getEventPayload();
-      payload.comment.unresolved = !this.$.resolvedCheckbox.checked;
-      this.fire('comment-update', payload);
-      if (!this.editing) {
-        // Save the resolved state immediately.
-        this.save(payload.comment);
-      }
-    }
-
-    _handleCommentDelete() {
-      this._openOverlay(this.confirmDeleteOverlay);
-    }
-
-    _handleCancelDeleteComment() {
-      this._closeOverlay(this.confirmDeleteOverlay);
-    }
-
-    _openOverlay(overlay) {
-      Polymer.dom(Gerrit.getRootElement()).appendChild(overlay);
-      return overlay.open();
-    }
-
-    _computeAuthorName(comment) {
-      if (!comment) return '';
-      if (comment.robot_id) {
-        return comment.robot_id;
-      }
-      return comment.author && comment.author.name;
-    }
-
-    _computeHideRunDetails(comment, collapsed) {
-      if (!comment) return true;
-      return !(comment.robot_id && comment.url && !collapsed);
-    }
-
-    _closeOverlay(overlay) {
-      Polymer.dom(Gerrit.getRootElement()).removeChild(overlay);
-      overlay.close();
-    }
-
-    _handleConfirmDeleteComment() {
-      const dialog =
-          this.confirmDeleteOverlay.querySelector('#confirmDeleteComment');
-      this.$.restAPI.deleteComment(
-          this.changeNum, this.patchNum, this.comment.id, dialog.message)
-          .then(newComment => {
-            this._handleCancelDeleteComment();
-            this.comment = newComment;
-          });
+    if (draft) {
+      this.set('comment.message', draft.message);
     }
   }
 
-  customElements.define(GrComment.is, GrComment);
-})();
+  _handleToggleResolved() {
+    this.$.reporting.recordDraftInteraction();
+    this.resolved = !this.resolved;
+    // Modify payload instead of this.comment, as this.comment is passed from
+    // the parent by ref.
+    const payload = this._getEventPayload();
+    payload.comment.unresolved = !this.$.resolvedCheckbox.checked;
+    this.fire('comment-update', payload);
+    if (!this.editing) {
+      // Save the resolved state immediately.
+      this.save(payload.comment);
+    }
+  }
+
+  _handleCommentDelete() {
+    this._openOverlay(this.confirmDeleteOverlay);
+  }
+
+  _handleCancelDeleteComment() {
+    this._closeOverlay(this.confirmDeleteOverlay);
+  }
+
+  _openOverlay(overlay) {
+    dom(Gerrit.getRootElement()).appendChild(overlay);
+    return overlay.open();
+  }
+
+  _computeAuthorName(comment) {
+    if (!comment) return '';
+    if (comment.robot_id) {
+      return comment.robot_id;
+    }
+    return comment.author && comment.author.name;
+  }
+
+  _computeHideRunDetails(comment, collapsed) {
+    if (!comment) return true;
+    return !(comment.robot_id && comment.url && !collapsed);
+  }
+
+  _closeOverlay(overlay) {
+    dom(Gerrit.getRootElement()).removeChild(overlay);
+    overlay.close();
+  }
+
+  _handleConfirmDeleteComment() {
+    const dialog =
+        this.confirmDeleteOverlay.querySelector('#confirmDeleteComment');
+    this.$.restAPI.deleteComment(
+        this.changeNum, this.patchNum, this.comment.id, dialog.message)
+        .then(newComment => {
+          this._handleCancelDeleteComment();
+          this.comment = newComment;
+        });
+  }
+}
+
+customElements.define(GrComment.is, GrComment);