Merge "Annotation updates"

This commit is contained in:
Becky Siegel
2017-08-14 17:08:20 +00:00
committed by Gerrit Code Review
77 changed files with 537 additions and 194 deletions

View File

@@ -22,6 +22,7 @@ limitations under the License.
/** @polymerBehavior Gerrit.BaseUrlBehavior */ /** @polymerBehavior Gerrit.BaseUrlBehavior */
Gerrit.BaseUrlBehavior = { Gerrit.BaseUrlBehavior = {
/** @return {string} */
getBaseUrl() { getBaseUrl() {
return window.CANONICAL_PATH || ''; return window.CANONICAL_PATH || '';
}, },

View File

@@ -22,7 +22,7 @@ limitations under the License.
<script src="../../bower_components/web-component-tester/browser.js"></script> <script src="../../bower_components/web-component-tester/browser.js"></script>
<link rel="import" href="../../test/common-test-setup.html"/> <link rel="import" href="../../test/common-test-setup.html"/>
<script> <script>
/** @type {String} */ /** @type {string} */
window.CANONICAL_PATH = '/r'; window.CANONICAL_PATH = '/r';
</script> </script>
<link rel="import" href="base-url-behavior.html"> <link rel="import" href="base-url-behavior.html">

View File

@@ -32,7 +32,7 @@ limitations under the License.
* Get the docs base URL from either the server config or by probing. * Get the docs base URL from either the server config or by probing.
* @param {Object} config The server config. * @param {Object} config The server config.
* @param {!Object} restApi A REST API instance * @param {!Object} restApi A REST API instance
* @return {!Promise<String>} A promise that resolves with the docs base * @return {!Promise<string>} A promise that resolves with the docs base
* URL. * URL.
*/ */
getDocsBaseUrl(config, restApi) { getDocsBaseUrl(config, restApi) {

View File

@@ -40,6 +40,7 @@ limitations under the License.
/** /**
* Returns the complement to the given column array * Returns the complement to the given column array
* @param {Array} columns * @param {Array} columns
* @return {!Array}
*/ */
getComplementColumns(columns) { getComplementColumns(columns) {
return this.columnNames.filter(column => { return this.columnNames.filter(column => {
@@ -47,6 +48,11 @@ limitations under the License.
}); });
}, },
/**
* @param {string} columnToCheck
* @param {!Array} columnsToDisplay
* @return {boolean}
*/
isColumnHidden(columnToCheck, columnsToDisplay) { isColumnHidden(columnToCheck, columnsToDisplay) {
return !columnsToDisplay.includes(columnToCheck); return !columnsToDisplay.includes(columnToCheck);
}, },

View File

@@ -35,11 +35,19 @@ limitations under the License.
return this.getBaseUrl() + path + this.encodeURL(item, true); return this.getBaseUrl() + path + this.encodeURL(item, true);
}, },
/**
* @param {Object} params
* @return {string}
*/
getFilterValue(params) { getFilterValue(params) {
if (!params) { return null; } if (!params) { return ''; }
return params.filter || null; return params.filter || '';
}, },
/**
* @param {Object} params
* @return {number}
*/
getOffsetValue(params) { getOffsetValue(params) {
if (params && params.offset) { if (params && params.offset) {
return params.offset; return params.offset;

View File

@@ -39,7 +39,9 @@ limitations under the License.
* this function checks for patchNum equality. * this function checks for patchNum equality.
* *
* @param {string|number} a * @param {string|number} a
* @param {string|number} b * @param {string|number|undefined} b Undefined sometimes because
* computeLatestPatchNum can return undefined.
* @return {boolean}
*/ */
patchNumEquals(a, b) { patchNumEquals(a, b) {
return a + '' === b + ''; return a + '' === b + '';
@@ -180,6 +182,7 @@ limitations under the License.
return patchNums; return patchNums;
}, },
/** @return {number|undefined} */
computeLatestPatchNum(allPatchSets) { computeLatestPatchNum(allPatchSets) {
if (!allPatchSets || !allPatchSets.length) { return undefined; } if (!allPatchSets || !allPatchSets.length) { return undefined; }
if (allPatchSets[allPatchSets.length - 1].num === if (allPatchSets[allPatchSets.length - 1].num ===

View File

@@ -20,6 +20,11 @@ limitations under the License.
window.Gerrit = window.Gerrit || {}; window.Gerrit = window.Gerrit || {};
/** @polymerBehavior Gerrit.PathListBehavior */ /** @polymerBehavior Gerrit.PathListBehavior */
Gerrit.PathListBehavior = { Gerrit.PathListBehavior = {
/**
* @param {string} a
* @param {string} b
* @return {number}
*/
specialFilePathCompare(a, b) { specialFilePathCompare(a, b) {
// The commit message always goes first. // The commit message always goes first.
const COMMIT_MESSAGE_PATH = '/COMMIT_MSG'; const COMMIT_MESSAGE_PATH = '/COMMIT_MSG';

View File

@@ -33,7 +33,7 @@
return 'ontouchstart' in document.documentElement; return 'ontouchstart' in document.documentElement;
}, },
}, },
_tooltip: Element, _tooltip: Object,
_titleText: String, _titleText: String,
_hasSetupTooltipListeners: { _hasSetupTooltipListeners: {
type: Boolean, type: Boolean,

View File

@@ -22,6 +22,8 @@ limitations under the License.
// Must be declared outside behavior implementation to be accessed inside // Must be declared outside behavior implementation to be accessed inside
// behavior functions. // behavior functions.
/** @return {!Object} */
const getKeyboardEvent = function(e) { const getKeyboardEvent = function(e) {
e = Polymer.dom(e.detail ? e.detail.keyboardEvent : e); e = Polymer.dom(e.detail ? e.detail.keyboardEvent : e);
// When e is a keyboardEvent, e.event is not null. // When e is a keyboardEvent, e.event is not null.
@@ -55,6 +57,7 @@ limitations under the License.
}, },
// Alias for getKeyboardEvent. // Alias for getKeyboardEvent.
/** @return {!Object} */
getKeyboardEvent(e) { getKeyboardEvent(e) {
return getKeyboardEvent(e); return getKeyboardEvent(e);
}, },

View File

@@ -101,6 +101,9 @@ limitations under the License.
return v.toString(16); return v.toString(16);
}, },
/**
* @return {string}
*/
changeBaseURL(changeNum, patchNum) { changeBaseURL(changeNum, patchNum) {
let v = this.getBaseUrl() + '/changes/' + changeNum; let v = this.getBaseUrl() + '/changes/' + changeNum;
if (patchNum) { if (patchNum) {

View File

@@ -22,7 +22,7 @@ limitations under the License.
<script src="../../bower_components/web-component-tester/browser.js"></script> <script src="../../bower_components/web-component-tester/browser.js"></script>
<link rel="import" href="../../test/common-test-setup.html"/> <link rel="import" href="../../test/common-test-setup.html"/>
<script> <script>
/** @type {String} */ /** @type {string} */
window.CANONICAL_PATH = '/r'; window.CANONICAL_PATH = '/r';
</script> </script>

View File

@@ -40,6 +40,7 @@
is: 'gr-admin-view', is: 'gr-admin-view',
properties: { properties: {
/** @type {?} */
params: Object, params: Object,
path: String, path: String,
adminView: String, adminView: String,
@@ -126,7 +127,7 @@
linkCopy.subsection = { linkCopy.subsection = {
name: this._groupName, name: this._groupName,
view: 'gr-group', view: 'gr-group',
url: `/admin/groups/${this.encodeURL(this._groupId, true)}`, url: `/admin/groups/${this.encodeURL(this._groupId + '', true)}`,
children: [], children: [],
}; };
if (this._groupOwner) { if (this._groupOwner) {
@@ -135,8 +136,8 @@
name: 'Audit Log', name: 'Audit Log',
detailType: 'audit-log', detailType: 'audit-log',
view: 'gr-group-audit-log', view: 'gr-group-audit-log',
url: `/admin/groups/${this.encodeURL(this._groupId, true)}` + url: '/admin/groups/' +
',audit-log', `${this.encodeURL(this._groupId + '', true)},audit-log`,
} }
); );
} }
@@ -198,6 +199,11 @@
return this._computeRelativeURL(link.url); return this._computeRelativeURL(link.url);
}, },
/**
* @param {string} itemView
* @param {Object} params
* @param {string=} opt_detailType
*/
_computeSelectedClass(itemView, params, opt_detailType) { _computeSelectedClass(itemView, params, opt_detailType) {
if (params.detailType && params.detailType !== opt_detailType) { if (params.detailType && params.detailType !== opt_detailType) {
return ''; return '';

View File

@@ -68,7 +68,7 @@
page.show(this._computeItemUrl(this.itemDetail)); page.show(this._computeItemUrl(this.itemDetail));
} }
}); });
} else if (this.itemDetail === DETAIL_TYPES.tag) { } else if (this.itemDetail === DETAIL_TYPES.tags) {
return this.$.restAPI.createProjectTag(this.projectName, return this.$.restAPI.createProjectTag(this.projectName,
this._itemName, {revision: USE_HEAD}) this._itemName, {revision: USE_HEAD})
.then(itemRegistered => { .then(itemRegistered => {

View File

@@ -25,12 +25,13 @@
value: false, value: false,
}, },
/** @type {?} */
_projectConfig: { _projectConfig: {
type: Object, type: Object,
value: () => { return {}; }, value: () => { return {}; },
}, },
_projectCreated: { _projectCreated: {
type: Object, type: Boolean,
value: false, value: false,
}, },

View File

@@ -61,6 +61,7 @@
value: false, value: false,
observer: '_loggedInChanged', observer: '_loggedInChanged',
}, },
/** @type {?} */
_groupConfig: Object, _groupConfig: Object,
_groupName: Object, _groupName: Object,
_groupOwner: { _groupOwner: {

View File

@@ -28,7 +28,10 @@
/** /**
* Offset of currently visible query results. * Offset of currently visible query results.
*/ */
_offset: Number, _offset: {
type: Number,
value: 0,
},
_path: { _path: {
type: String, type: String,
readOnly: true, readOnly: true,
@@ -51,7 +54,10 @@
type: Boolean, type: Boolean,
value: true, value: true,
}, },
_filter: String, _filter: {
type: String,
value: '',
},
}, },
behaviors: [ behaviors: [

View File

@@ -73,6 +73,8 @@
_filter: String, _filter: String,
_refName: String, _refName: String,
_hasNewItemName: Boolean, _hasNewItemName: Boolean,
_isEditing: Boolean,
_revisedRef: String,
}, },
behaviors: [ behaviors: [

View File

@@ -67,6 +67,7 @@
value: false, value: false,
observer: '_loggedInChanged', observer: '_loggedInChanged',
}, },
/** @type {?} */
_projectConfig: Object, _projectConfig: Object,
_readOnly: { _readOnly: {
type: Boolean, type: Boolean,

View File

@@ -22,6 +22,8 @@
labelNames: { labelNames: {
type: Array, type: Array,
}, },
/** @type {?} */
change: Object, change: Object,
changeURL: { changeURL: {
type: String, type: String,
@@ -31,6 +33,7 @@
type: Boolean, type: Boolean,
value: false, value: false,
}, },
showNumber: Boolean,
}, },
behaviors: [ behaviors: [

View File

@@ -54,6 +54,11 @@
/** /**
* State persisted across restamps of the element. * State persisted across restamps of the element.
*
* Need sub-property declaration since it is used in template before
* assignment.
* @type {{ selectedChangeIndex: (number|undefined) }}
*
*/ */
viewState: { viewState: {
type: Object, type: Object,

View File

@@ -99,7 +99,6 @@ limitations under the License.
needs-review$="[[_computeItemNeedsReview(account, change, showReviewedState)]]" needs-review$="[[_computeItemNeedsReview(account, change, showReviewedState)]]"
change="[[change]]" change="[[change]]"
visible-change-table-columns="[[visibleChangeTableColumns]]" visible-change-table-columns="[[visibleChangeTableColumns]]"
show-number="[[showNumber]]"
show-star="[[showStar]]" show-star="[[showStar]]"
label-names="[[labelNames]]"></gr-change-list-item> label-names="[[labelNames]]"></gr-change-list-item>
</template> </template>

View File

@@ -86,6 +86,7 @@
value() { return document.body; }, value() { return document.body; },
}, },
changeTableColumns: Array, changeTableColumns: Array,
visibleChangeTableColumns: Array,
}, },
behaviors: [ behaviors: [

View File

@@ -49,6 +49,7 @@
type: Object, type: Object,
value() { return {}; }, value() { return {}; },
}, },
/** @type {{ selectedChangeIndex: number }} */
viewState: Object, viewState: Object,
params: { params: {
type: Object, type: Object,

View File

@@ -34,6 +34,9 @@
change: Object, change: Object,
filter: Function, filter: Function,
placeholder: String, placeholder: String,
/**
* Needed for template checking since value is initially set to null.
* @type {?Object} */
pendingConfirmation: { pendingConfirmation: {
type: Object, type: Object,
value: null, value: null,

View File

@@ -18,7 +18,7 @@
const ERR_COMMIT_EMPTY = 'The commit message cant be empty.'; const ERR_COMMIT_EMPTY = 'The commit message cant be empty.';
const ERR_REVISION_ACTIONS = 'Couldnt load revision actions.'; const ERR_REVISION_ACTIONS = 'Couldnt load revision actions.';
/** /**
* @enum {number} * @enum {string}
*/ */
const LabelStatus = { const LabelStatus = {
/** /**
@@ -44,6 +44,7 @@
* project owner or site administrator. * project owner or site administrator.
*/ */
IMPOSSIBLE: 'IMPOSSIBLE', IMPOSSIBLE: 'IMPOSSIBLE',
OPTIONAL: 'OPTIONAL',
}; };
// TODO(davido): Add the rest of the change actions. // TODO(davido): Add the rest of the change actions.
@@ -139,6 +140,7 @@
*/ */
properties: { properties: {
/** @type {{ branch: string, project: string }} */
change: Object, change: Object,
actions: { actions: {
type: Object, type: Object,
@@ -169,6 +171,7 @@
type: String, type: String,
value: '', value: '',
}, },
/** @type {?} */
revisionActions: { revisionActions: {
type: Object, type: Object,
value() { return {}; }, value() { return {}; },
@@ -180,7 +183,7 @@
}, },
_actionLoadingMessage: { _actionLoadingMessage: {
type: String, type: String,
value: null, value: '',
}, },
_allActionValues: { _allActionValues: {
type: Array, type: Array,
@@ -417,7 +420,7 @@
this.hidden = this._keyCount(actionsChangeRecord) === 0 && this.hidden = this._keyCount(actionsChangeRecord) === 0 &&
this._keyCount(revisionActionsChangeRecord) === 0 && this._keyCount(revisionActionsChangeRecord) === 0 &&
additionalActions.length === 0; additionalActions.length === 0;
this._actionLoadingMessage = null; this._actionLoadingMessage = '';
this._disabledMenuActions = []; this._disabledMenuActions = [];
const revisionActions = revisionActionsChangeRecord.base || {}; const revisionActions = revisionActionsChangeRecord.base || {};
@@ -449,7 +452,7 @@
* Get highest score for last missing permitted label for current change. * Get highest score for last missing permitted label for current change.
* Returns null if no labels permitted or more than one label missing. * Returns null if no labels permitted or more than one label missing.
* *
* @return {{label: string, score: string}} * @return {{label: string, score: string}|null}
*/ */
_getTopMissingApproval() { _getTopMissingApproval() {
if (!this.change || if (!this.change ||
@@ -668,9 +671,8 @@
}, },
/** /**
* Returns true if hasParent is defined (can be either true or false). * _hasKnownChainState set to true true if hasParent is defined (can be
* returns false otherwise. * either true or false). set to false otherwise.
* @return {boolean} hasParent
*/ */
_computeChainState(hasParent) { _computeChainState(hasParent) {
this._hasKnownChainState = true; this._hasKnownChainState = true;
@@ -778,7 +780,7 @@
if (this._getActionOverflowIndex(type, key) !== -1) { if (this._getActionOverflowIndex(type, key) !== -1) {
this.push('_disabledMenuActions', key === '/' ? 'delete' : key); this.push('_disabledMenuActions', key === '/' ? 'delete' : key);
return function() { return function() {
this._actionLoadingMessage = null; this._actionLoadingMessage = '';
this._disabledMenuActions = []; this._disabledMenuActions = [];
}.bind(this); }.bind(this);
} }
@@ -788,12 +790,18 @@
buttonEl.setAttribute('loading', true); buttonEl.setAttribute('loading', true);
buttonEl.disabled = true; buttonEl.disabled = true;
return function() { return function() {
this._actionLoadingMessage = null; this._actionLoadingMessage = '';
buttonEl.removeAttribute('loading'); buttonEl.removeAttribute('loading');
buttonEl.disabled = false; buttonEl.disabled = false;
}.bind(this); }.bind(this);
}, },
/**
* @param {string} endpoint
* @param {!Object|undefined} action
* @param {boolean} revAction
* @param {!Object|string=} opt_payload
*/
_fireAction(endpoint, action, revAction, opt_payload) { _fireAction(endpoint, action, revAction, opt_payload) {
const cleanupFn = const cleanupFn =
this._setLoadingOnButtonWithKey(action.__type, action.__key); this._setLoadingOnButtonWithKey(action.__type, action.__key);
@@ -861,6 +869,14 @@
}); });
}, },
/**
* @param {string} method
* @param {string|!Object|undefined} payload
* @param {string} actionEndpoint
* @param {boolean} revisionAction
* @param {?Function} cleanupFn
* @param {?Function=} opt_errorFn
*/
_send(method, payload, actionEndpoint, revisionAction, cleanupFn, _send(method, payload, actionEndpoint, revisionAction, cleanupFn,
opt_errorFn) { opt_errorFn) {
return this.fetchIsLatestKnown(this.change, this.$.restAPI) return this.fetchIsLatestKnown(this.change, this.$.restAPI)
@@ -918,19 +934,19 @@
/** /**
* Merge sources of change actions into a single ordered array of action * Merge sources of change actions into a single ordered array of action
* values. * values.
* @param {splices} changeActionsRecord * @param {!Array} changeActionsRecord
* @param {splices} revisionActionsRecord * @param {!Array} revisionActionsRecord
* @param {splices} primariesRecord * @param {!Array} primariesRecord
* @param {splices} additionalActionsRecord * @param {!Array} additionalActionsRecord
* @param {Object} change The change object. * @param {!Object} change The change object.
* @return {Array} * @return {!Array}
*/ */
_computeAllActions(changeActionsRecord, revisionActionsRecord, _computeAllActions(changeActionsRecord, revisionActionsRecord,
primariesRecord, additionalActionsRecord, change) { primariesRecord, additionalActionsRecord, change) {
const revisionActionValues = this._getActionValues(revisionActionsRecord, const revisionActionValues = this._getActionValues(revisionActionsRecord,
primariesRecord, additionalActionsRecord, ActionType.REVISION); primariesRecord, additionalActionsRecord, ActionType.REVISION);
const changeActionValues = this._getActionValues(changeActionsRecord, const changeActionValues = this._getActionValues(changeActionsRecord,
primariesRecord, additionalActionsRecord, ActionType.CHANGE, change); primariesRecord, additionalActionsRecord, ActionType.CHANGE);
const quickApprove = this._getQuickApproveAction(); const quickApprove = this._getQuickApproveAction();
if (quickApprove) { if (quickApprove) {
changeActionValues.unshift(quickApprove); changeActionValues.unshift(quickApprove);

View File

@@ -34,9 +34,13 @@
*/ */
properties: { properties: {
/** @type {?} */
change: Object, change: Object,
commitInfo: Object, commitInfo: Object,
mutable: Boolean, mutable: Boolean,
/**
* @type {{ note_db_enabled: string }}
*/
serverConfig: Object, serverConfig: Object,
_topicReadOnly: { _topicReadOnly: {
type: Boolean, type: Boolean,
@@ -235,6 +239,13 @@
return false; return false;
}, },
/**
* Closure annotation for Polymer.prototype.splice is off.
* For now, supressing annotations.
*
* TODO(beckysiegel) submit Polymer PR
*
* @suppress {checkTypes} */
_onDeleteVote(e) { _onDeleteVote(e) {
e.preventDefault(); e.preventDefault();
const target = Polymer.dom(e).rootTarget; const target = Polymer.dom(e).rootTarget;

View File

@@ -68,6 +68,7 @@
type: Object, type: Object,
observer: '_paramsChanged', observer: '_paramsChanged',
}, },
/** @type {?} */
viewState: { viewState: {
type: Object, type: Object,
notify: true, notify: true,
@@ -80,6 +81,7 @@
type: Object, type: Object,
value() { return document.body; }, value() { return document.body; },
}, },
/** @type {?} */
_serverConfig: { _serverConfig: {
type: Object, type: Object,
observer: '_startUpdateCheckTimer', observer: '_startUpdateCheckTimer',
@@ -99,10 +101,12 @@
computed: '_computeCanStartReview(_loggedIn, _change, _account)', computed: '_computeCanStartReview(_loggedIn, _change, _account)',
}, },
_comments: Object, _comments: Object,
/** @type {?} */
_change: { _change: {
type: Object, type: Object,
observer: '_changeChanged', observer: '_changeChanged',
}, },
/** @type {?} */
_commitInfo: Object, _commitInfo: Object,
_files: Object, _files: Object,
_changeNum: String, _changeNum: String,
@@ -119,6 +123,7 @@
computed: '_computeHideEditCommitMessage(_loggedIn, ' + computed: '_computeHideEditCommitMessage(_loggedIn, ' +
'_editingCommitMessage, _change)', '_editingCommitMessage, _change)',
}, },
/** @type {?string} */
_latestCommitMessage: { _latestCommitMessage: {
type: String, type: String,
value: '', value: '',
@@ -129,6 +134,7 @@
computed: computed:
'_computeChangeIdCommitMessageError(_latestCommitMessage, _change)', '_computeChangeIdCommitMessageError(_latestCommitMessage, _change)',
}, },
/** @type {?} */
_patchRange: { _patchRange: {
type: Object, type: Object,
observer: '_updateSelected', observer: '_updateSelected',
@@ -147,6 +153,7 @@
value: false, value: false,
}, },
_loading: Boolean, _loading: Boolean,
/** @type {?} */
_projectConfig: Object, _projectConfig: Object,
_rebaseOnCurrent: Boolean, _rebaseOnCurrent: Boolean,
_replyButtonLabel: { _replyButtonLabel: {
@@ -180,6 +187,7 @@
type: Boolean, type: Boolean,
value: true, value: true,
}, },
/** @type {?number} */
_updateCheckTimerHandle: Number, _updateCheckTimerHandle: Number,
_sortedRevisions: Array, _sortedRevisions: Array,
_editLoaded: { _editLoaded: {
@@ -715,7 +723,7 @@
const t = labels[labelName]; const t = labels[labelName];
if (!t) { return result; } if (!t) { return result; }
const approvals = t.all || []; const approvals = t.all || [];
for (label of approvals) { for (const label of approvals) {
if (label.value && label.value != labels[labelName].default_value) { if (label.value && label.value != labels[labelName].default_value) {
let labelClassName; let labelClassName;
let labelValPrefix = ''; let labelValPrefix = '';
@@ -853,6 +861,9 @@
}); });
}, },
/**
* @param {string=} opt_section
*/
_openReplyDialog(opt_section) { _openReplyDialog(opt_section) {
this.$.replyOverlay.open().then(() => { this.$.replyOverlay.open().then(() => {
this.$.replyOverlay.setFocusStops(this.$.replyDialog.getFocusStops()); this.$.replyOverlay.setFocusStops(this.$.replyDialog.getFocusStops());
@@ -946,7 +957,10 @@
this._latestCommitMessage = null; this._latestCommitMessage = null;
} }
const lineHeight = getComputedStyle(this).lineHeight; const lineHeight = getComputedStyle(this).lineHeight;
this._lineHeight = lineHeight.slice(0, lineHeight.length - 2);
// Slice returns a number as a string, convert to an int.
this._lineHeight =
parseInt(lineHeight.slice(0, lineHeight.length - 2), 10);
this._change = change; this._change = change;
if (!this._patchRange || !this._patchRange.patchNum || if (!this._patchRange || !this._patchRange.patchNum ||
@@ -1122,9 +1136,9 @@
/** /**
* @param {Object} revisions The revisions object keyed by revision hashes * @param {!Object} revisions The revisions object keyed by revision hashes
* @param {Object} patchSet A revision already fetched from {revisions} * @param {?Object} patchSet A revision already fetched from {revisions}
* @return {string} the SHA hash corresponding to the revision. * @return {string|undefined} the SHA hash corresponding to the revision.
*/ */
_getPatchsetHash(revisions, patchSet) { _getPatchsetHash(revisions, patchSet) {
for (const rev in revisions) { for (const rev in revisions) {
@@ -1304,7 +1318,9 @@
}, },
_cancelUpdateCheckTimer() { _cancelUpdateCheckTimer() {
this.cancelAsync(this._updateCheckTimerHandle); if (this._updateCheckTimerHandle) {
this.cancelAsync(this._updateCheckTimerHandle);
}
this._updateCheckTimerHandle = null; this._updateCheckTimerHandle = null;
}, },

View File

@@ -32,6 +32,8 @@
patchNum: Number, patchNum: Number,
commentLinks: Object, commentLinks: Object,
projectName: String, projectName: String,
/** @type {?} */
projectConfig: Object,
}, },
_computeFilesFromComments(comments) { _computeFilesFromComments(comments) {

View File

@@ -30,6 +30,10 @@
*/ */
properties: { properties: {
/**
* Weird API usage requires this to be String or Null. Add this so
* the closure compiler doesn't complain.
* @type {?string} */
base: String, base: String,
branch: String, branch: String,
hasParent: Boolean, hasParent: Boolean,
@@ -62,7 +66,7 @@
this.fire('cancel', null, {bubbles: false}); this.fire('cancel', null, {bubbles: false});
}, },
_handleRebaseOnOther(e) { _handleRebaseOnOther() {
this.$.parentInput.focus(); this.$.parentInput.focus();
}, },
@@ -73,15 +77,15 @@
* rebased on top of the target branch. Leaving out the base implies that it * rebased on top of the target branch. Leaving out the base implies that it
* should be rebased on top of its current parent. * should be rebased on top of its current parent.
*/ */
_handleRebaseOnTip(e) { _handleRebaseOnTip() {
this.base = ''; this.base = '';
}, },
_handleRebaseOnParent(e) { _handleRebaseOnParent() {
this.base = null; this.base = null;
}, },
_handleEnterChangeNumberTap(e) { _handleEnterChangeNumberTap() {
this.$.rebaseOnOtherInput.checked = true; this.$.rebaseOnOtherInput.checked = true;
}, },

View File

@@ -24,8 +24,10 @@
*/ */
properties: { properties: {
/** @type {{ revisions: Array }} */
change: Object, change: Object,
patchNum: String, patchNum: String,
/** @type {?} */
config: Object, config: Object,
_schemes: { _schemes: {
@@ -82,28 +84,55 @@
return commands; return commands;
}, },
/**
* @param {!Object} change
* @param {number|string} patchNum
*
* @return {string}
*/
_computeZipDownloadLink(change, patchNum) { _computeZipDownloadLink(change, patchNum) {
return this._computeDownloadLink(change, patchNum, true); return this._computeDownloadLink(change, patchNum, true);
}, },
/**
* @param {!Object} change
* @param {number|string} patchNum
*
* @return {string}
*/
_computeZipDownloadFilename(change, patchNum) { _computeZipDownloadFilename(change, patchNum) {
return this._computeDownloadFilename(change, patchNum, true); return this._computeDownloadFilename(change, patchNum, true);
}, },
_computeDownloadLink(change, patchNum, zip) { /**
* @param {!Object} change
* @param {number|string} patchNum
* @param {boolean=} opt_zip
*
* @return {string} Not sure why there was a mismatch
*/
_computeDownloadLink(change, patchNum, opt_zip) {
return this.changeBaseURL(change._number, patchNum) + '/patch?' + return this.changeBaseURL(change._number, patchNum) + '/patch?' +
(zip ? 'zip' : 'download'); (opt_zip ? 'zip' : 'download');
}, },
_computeDownloadFilename(change, patchNum, zip) {
let shortRev; /**
* @param {!Object} change
* @param {number|string} patchNum
* @param {boolean=} opt_zip
*
* @return {string}
*/
_computeDownloadFilename(change, patchNum, opt_zip) {
let shortRev = '';
for (const rev in change.revisions) { for (const rev in change.revisions) {
if (this.patchNumEquals(change.revisions[rev]._number, patchNum)) { if (this.patchNumEquals(change.revisions[rev]._number, patchNum)) {
shortRev = rev.substr(0, 7); shortRev = rev.substr(0, 7);
break; break;
} }
} }
return shortRev + '.diff.' + (zip ? 'zip' : 'base64'); return shortRev + '.diff.' + (opt_zip ? 'zip' : 'base64');
}, },
_computeArchiveDownloadLink(change, patchNum, format) { _computeArchiveDownloadLink(change, patchNum, format) {

View File

@@ -35,6 +35,7 @@
is: 'gr-file-list', is: 'gr-file-list',
properties: { properties: {
/** @type {?} */
patchRange: { patchRange: {
type: Object, type: Object,
observer: '_updateSelected', observer: '_updateSelected',
@@ -54,6 +55,7 @@
type: Object, type: Object,
value() { return document.body; }, value() { return document.body; },
}, },
/** @type {?} */
change: Object, change: Object,
diffViewMode: { diffViewMode: {
type: String, type: String,
@@ -80,6 +82,7 @@
notify: true, notify: true,
observer: '_updateDiffPreferences', observer: '_updateDiffPreferences',
}, },
/** @type {?} */
_userPrefs: Object, _userPrefs: Object,
_localPrefs: Object, _localPrefs: Object,
_showInlineDiffs: Boolean, _showInlineDiffs: Boolean,
@@ -87,6 +90,7 @@
type: Number, type: Number,
notify: true, notify: true,
}, },
/** @type {?} */
_patchChange: { _patchChange: {
type: Object, type: Object,
computed: '_calculatePatchChange(_files)', computed: '_calculatePatchChange(_files)',
@@ -283,7 +287,7 @@
} }
}, },
_expandAllDiffs(e) { _expandAllDiffs() {
this._showInlineDiffs = true; this._showInlineDiffs = true;
// Find the list of paths that are in the file list, but not in the // Find the list of paths that are in the file list, but not in the
@@ -300,7 +304,7 @@
this.splice(...['_expandedFilePaths', 0, 0].concat(newPaths)); this.splice(...['_expandedFilePaths', 0, 0].concat(newPaths));
}, },
_collapseAllDiffs(e) { _collapseAllDiffs() {
this._showInlineDiffs = false; this._showInlineDiffs = false;
this._expandedFilePaths = []; this._expandedFilePaths = [];
this.$.diffCursor.handleDiffUpdate(); this.$.diffCursor.handleDiffUpdate();
@@ -330,6 +334,12 @@
}); });
}, },
/**
* @param {!Array} comments
* @param {number} patchNum
* @param {string} path
* @param {string=} opt_noun
*/
_computeCountString(comments, patchNum, path, opt_noun) { _computeCountString(comments, patchNum, path, opt_noun) {
if (!comments) { return ''; } if (!comments) { return ''; }
@@ -345,8 +355,8 @@
* Computes a string counting the number of unresolved comment threads in a * Computes a string counting the number of unresolved comment threads in a
* given file and path. * given file and path.
* *
* @param {Object} comments * @param {!Object} comments
* @param {Object} drafts * @param {!Object} drafts
* @param {number} patchNum * @param {number} patchNum
* @param {string} path * @param {string} path
* @return {string} * @return {string}
@@ -642,6 +652,9 @@
diff.patchRange.patchNum, this.patchRange.basePatchNum); diff.patchRange.patchNum, this.patchRange.basePatchNum);
}, },
/**
* @param {number=} opt_index
*/
_openSelectedFile(opt_index) { _openSelectedFile(opt_index) {
if (opt_index != null) { if (opt_index != null) {
this.$.fileCursor.setCursorAtIndex(opt_index); this.$.fileCursor.setCursorAtIndex(opt_index);
@@ -816,7 +829,7 @@
* *
* Use side-by-side if there is no view mode or preferences. * Use side-by-side if there is no view mode or preferences.
* *
* @return {String} * @return {string}
*/ */
_getDiffViewMode(diffViewMode, userPrefs) { _getDiffViewMode(diffViewMode, userPrefs) {
if (diffViewMode) { if (diffViewMode) {
@@ -858,7 +871,7 @@
* entries in the expanded list, then render each diff corresponding in * entries in the expanded list, then render each diff corresponding in
* order by waiting for the previous diff to finish before starting the next * order by waiting for the previous diff to finish before starting the next
* one. * one.
* @param {splice} record The splice record in the expanded paths list. * @param {!Array} record The splice record in the expanded paths list.
*/ */
_expandedPathsChanged(record) { _expandedPathsChanged(record) {
if (!record) { return; } if (!record) { return; }
@@ -890,9 +903,9 @@
* Given an array of paths and a NodeList of diff elements, render the diff * Given an array of paths and a NodeList of diff elements, render the diff
* for each path in order, awaiting the previous render to complete before * for each path in order, awaiting the previous render to complete before
* continung. * continung.
* @param {!Array<!String>} paths * @param {!Array<string>} paths
* @param {!NodeList<!GrDiffElement>} diffElements * @param {!NodeList<!Object>} diffElements (GrDiffElement)
* @param {Number} initialCount The total number of paths in the pass. This * @param {number} initialCount The total number of paths in the pass. This
* is used to generate log messages. * is used to generate log messages.
* @return {!Promise} * @return {!Promise}
*/ */
@@ -918,9 +931,9 @@
/** /**
* In the given NodeList of diff elements, find the diff for the given path. * In the given NodeList of diff elements, find the diff for the given path.
* @param {!String} path * @param {string} path
* @param {!NodeList<!GrDiffElement>} diffElements * @param {!NodeList<!Object>} diffElements (GrDiffElement)
* @return {!GrDiffElement} * @return {!Object|undefined} (GrDiffElement)
*/ */
_findDiffByPath(path, diffElements) { _findDiffByPath(path, diffElements) {
for (let i = 0; i < diffElements.length; i++) { for (let i = 0; i < diffElements.length; i++) {
@@ -941,13 +954,13 @@
* Update the loading class for the file list rows. The update is inside a * Update the loading class for the file list rows. The update is inside a
* debouncer so that the file list doesn't flash gray when the API requests * debouncer so that the file list doesn't flash gray when the API requests
* are reasonably fast. * are reasonably fast.
* @param {string} loading * @param {boolean} loading
*/ */
_loadingChanged(loading) { _loadingChanged(loading) {
this.debounce('loading-change', () => { this.debounce('loading-change', () => {
// Only show set the loading if there have been files loaded to show. In // Only show set the loading if there have been files loaded to show. In
// this way, the gray loading style is not shown on initial loads. // this way, the gray loading style is not shown on initial loads.
this.classList.toggle('loading', loading && this._files.length); this.classList.toggle('loading', loading && !!this._files.length);
}, LOADING_DEBOUNCE_INTERVAL); }, LOADING_DEBOUNCE_INTERVAL);
}, },

View File

@@ -17,6 +17,9 @@
Polymer({ Polymer({
is: 'gr-label-score-row', is: 'gr-label-score-row',
properties: { properties: {
/**
* @type {{ name: string }}
*/
label: Object, label: Object,
labels: Object, labels: Object,
name: { name: {
@@ -54,12 +57,12 @@
_computeBlankItems(permittedLabels, label, side) { _computeBlankItems(permittedLabels, label, side) {
if (!permittedLabels || !permittedLabels[label]) { return []; } if (!permittedLabels || !permittedLabels[label]) { return []; }
const startPosition = this.labelValues[parseInt( const startPosition = this.labelValues[parseInt(
permittedLabels[label][0])]; permittedLabels[label][0], 10)];
if (side === 'start') { if (side === 'start') {
return new Array(startPosition); return new Array(startPosition);
} }
const endPosition = this.labelValues[parseInt( const endPosition = this.labelValues[parseInt(
permittedLabels[label][permittedLabels[label].length - 1])]; permittedLabels[label][permittedLabels[label].length - 1], 10)];
return new Array(Object.keys(this.labelValues).length - endPosition - 1); return new Array(Object.keys(this.labelValues).length - endPosition - 1);
}, },

View File

@@ -25,6 +25,7 @@
type: Object, type: Object,
observer: '_computeColumns', observer: '_computeColumns',
}, },
/** @type {?} */
change: Object, change: Object,
_labelValues: Object, _labelValues: Object,
}, },

View File

@@ -39,6 +39,7 @@
properties: { properties: {
changeNum: Number, changeNum: Number,
/** @type {?} */
message: Object, message: Object,
author: { author: {
type: Object, type: Object,
@@ -79,6 +80,10 @@
observer: '_projectNameChanged', observer: '_projectNameChanged',
}, },
_commentLinks: Object, _commentLinks: Object,
/**
* @type {{ commentlinks: Array }}
*/
projectConfig: Object,
// Computed property needed to trigger Polymer value observing. // Computed property needed to trigger Polymer value observing.
_expanded: { _expanded: {
type: Object, type: Object,

View File

@@ -22,6 +22,7 @@
hasParent: { hasParent: {
type: Boolean, type: Boolean,
notify: true, notify: true,
value: false,
}, },
patchNum: String, patchNum: String,
parentChange: Object, parentChange: Object,
@@ -39,6 +40,7 @@
computed: '_computeConnectedRevisions(change, patchNum, ' + computed: '_computeConnectedRevisions(change, patchNum, ' +
'_relatedResponse.changes)', '_relatedResponse.changes)',
}, },
/** @type {?} */
_relatedResponse: { _relatedResponse: {
type: Object, type: Object,
value() { return {changes: []}; }, value() { return {changes: []}; },
@@ -124,9 +126,9 @@
* Determines whether or not the given change has a parent change. If there * Determines whether or not the given change has a parent change. If there
* is a relation chain, and the change id is not the last item of the * is a relation chain, and the change id is not the last item of the
* relation chain, there is a parent. * relation chain, there is a parent.
* @param {Number} currentChangeId * @param {number} currentChangeId
* @param {Array} relatedChanges * @param {!Array} relatedChanges
* @return {Boolean} * @return {boolean}
*/ */
_calculateHasParent(currentChangeId, relatedChanges) { _calculateHasParent(currentChangeId, relatedChanges) {
return relatedChanges.length > 0 && return relatedChanges.length > 0 &&

View File

@@ -74,6 +74,9 @@
*/ */
properties: { properties: {
/**
* @type {{ _number: number, removable_reviewers: Array }}
*/
change: Object, change: Object,
patchNum: String, patchNum: String,
canBeStarted: { canBeStarted: {
@@ -95,12 +98,14 @@
value: '', value: '',
}, },
diffDrafts: Object, diffDrafts: Object,
/** @type {!Function} */
filterReviewerSuggestion: { filterReviewerSuggestion: {
type: Function, type: Function,
value() { value() {
return this._filterReviewerSuggestionGenerator(false); return this._filterReviewerSuggestionGenerator(false);
}, },
}, },
/** @type {!Function} */
filterCCSuggestion: { filterCCSuggestion: {
type: Function, type: Function,
value() { value() {
@@ -108,7 +113,13 @@
}, },
}, },
permittedLabels: Object, permittedLabels: Object,
/**
* @type {{ note_db_enabled: boolean }}
*/
serverConfig: Object, serverConfig: Object,
/**
* @type {{ commentlinks: Array }}
*/
projectConfig: Object, projectConfig: Object,
knownLatestState: String, knownLatestState: String,
underReview: { underReview: {
@@ -118,6 +129,7 @@
_account: Object, _account: Object,
_ccs: Array, _ccs: Array,
/** @type {?Object} */
_ccPendingConfirmation: { _ccPendingConfirmation: {
type: Object, type: Object,
observer: '_reviewerPendingConfirmationUpdated', observer: '_reviewerPendingConfirmationUpdated',
@@ -127,12 +139,14 @@
computed: '_computeMessagePlaceholder(canBeStarted)', computed: '_computeMessagePlaceholder(canBeStarted)',
}, },
_owner: Object, _owner: Object,
/** @type {?} */
_pendingConfirmationDetails: Object, _pendingConfirmationDetails: Object,
_includeComments: { _includeComments: {
type: Boolean, type: Boolean,
value: true, value: true,
}, },
_reviewers: Array, _reviewers: Array,
/** @type {?Object} */
_reviewerPendingConfirmation: { _reviewerPendingConfirmation: {
type: Object, type: Object,
observer: '_reviewerPendingConfirmationUpdated', observer: '_reviewerPendingConfirmationUpdated',
@@ -296,8 +310,8 @@
* Resets the state of the _reviewersPendingRemove object, and removes * Resets the state of the _reviewersPendingRemove object, and removes
* accounts if necessary. * accounts if necessary.
* *
* @param {Boolean} isCancel true if the action is a cancel. * @param {boolean} isCancel true if the action is a cancel.
* @param {Object} opt_accountIdsTransferred map of account IDs that must * @param {Object=} opt_accountIdsTransferred map of account IDs that must
* not be removed, because they have been readded in another state. * not be removed, because they have been readded in another state.
*/ */
_purgeReviewersPendingRemove(isCancel, opt_accountIdsTransferred) { _purgeReviewersPendingRemove(isCancel, opt_accountIdsTransferred) {
@@ -322,8 +336,11 @@
* Removes an account from the change, both on the backend and the client. * Removes an account from the change, both on the backend and the client.
* Does nothing if the account is a pending addition. * Does nothing if the account is a pending addition.
* *
* @param {Object} account * @param {!Object} account
* @param {ReviewerTypes} type * @param {string} type
*
* * TODO(beckysiegel) submit Polymer PR
* @suppress {checkTypes}
*/ */
_removeAccount(account, type) { _removeAccount(account, type) {
if (account._pendingAdd) { return; } if (account._pendingAdd) { return; }
@@ -605,8 +622,8 @@
* Generates a function to filter out reviewer/CC entries. When isCCs is * Generates a function to filter out reviewer/CC entries. When isCCs is
* truthy, the function filters out entries that already exist in this._ccs. * truthy, the function filters out entries that already exist in this._ccs.
* When falsy, the function filters entries that exist in this._reviewers. * When falsy, the function filters entries that exist in this._reviewers.
* @param {Boolean} isCCs * @param {boolean} isCCs
* @return {Function} * @return {!Function}
*/ */
_filterReviewerSuggestionGenerator(isCCs) { _filterReviewerSuggestionGenerator(isCCs) {
return suggestion => { return suggestion => {

View File

@@ -47,7 +47,7 @@
if (cfg && cfg.auth && cfg.auth.switch_account_url) { if (cfg && cfg.auth && cfg.auth.switch_account_url) {
this._switchAccountUrl = cfg.auth.switch_account_url; this._switchAccountUrl = cfg.auth.switch_account_url;
} else { } else {
this._switchAccountUrl = null; this._switchAccountUrl = '';
} }
this._hasAvatars = !!(cfg && cfg.plugin && cfg.plugin.has_avatars); this._hasAvatars = !!(cfg && cfg.plugin && cfg.plugin.has_avatars);
}); });

View File

@@ -36,7 +36,9 @@
*/ */
knownAccountId: Number, knownAccountId: Number,
_alertElement: Element, /** @type {?Object} */
_alertElement: Object,
/** @type {?number} */
_hideAlertHandle: Number, _hideAlertHandle: Number,
_refreshingCredentials: { _refreshingCredentials: {
type: Boolean, type: Boolean,
@@ -116,12 +118,18 @@
return this.$.restAPI.getLoggedIn(); return this.$.restAPI.getLoggedIn();
}, },
/**
* @param {string} text
* @param {?string=} opt_actionText
* @param {?Function=} opt_actionCallback
* @param {?boolean=} opt_dismissOnNavigation
*/
_showAlert(text, opt_actionText, opt_actionCallback, _showAlert(text, opt_actionText, opt_actionCallback,
dismissOnNavigation) { opt_dismissOnNavigation) {
if (this._alertElement) { return; } if (this._alertElement) { return; }
this._clearHideAlertHandle(); this._clearHideAlertHandle();
if (dismissOnNavigation) { if (opt_dismissOnNavigation) {
// Persist alert until navigation. // Persist alert until navigation.
this.listen(document, 'location-change', '_hideAlert'); this.listen(document, 'location-change', '_hideAlert');
} else { } else {

View File

@@ -72,6 +72,7 @@
notify: true, notify: true,
}, },
/** @type {?Object} */
_account: Object, _account: Object,
_adminLinks: { _adminLinks: {
type: Array, type: Array,
@@ -125,11 +126,12 @@
}, },
_handleLocationChange(e) { _handleLocationChange(e) {
if (this.getBaseUrl()) { const baseUrl = this.getBaseUrl();
if (baseUrl) {
// Strip the canonical path from the path since needing canonical in // Strip the canonical path from the path since needing canonical in
// the path is uneeded and breaks the url. // the path is uneeded and breaks the url.
this._loginURL = this.getBaseUrl() + '/login/' + encodeURIComponent( this._loginURL = baseUrl + '/login/' + encodeURIComponent(
'/' + window.location.pathname.substring(this.getBaseUrl().length) + '/' + window.location.pathname.substring(baseUrl.length) +
window.location.search + window.location.search +
window.location.hash); window.location.hash);
} else { } else {

View File

@@ -85,6 +85,10 @@ limitations under the License.
*/ */
_upgradeUrl: uninitialized, _upgradeUrl: uninitialized,
/**
* @param {number=} patchNum
* @param {number|string=} basePatchNum
*/
_checkPatchRange(patchNum, basePatchNum) { _checkPatchRange(patchNum, basePatchNum) {
if (basePatchNum && !patchNum) { if (basePatchNum && !patchNum) {
throw new Error('Cannot use base patch number without patch number.'); throw new Error('Cannot use base patch number without patch number.');
@@ -195,7 +199,6 @@ limitations under the License.
* @param {number=} opt_patchNum * @param {number=} opt_patchNum
* @param {number|string=} opt_basePatchNum The string 'PARENT' can be * @param {number|string=} opt_basePatchNum The string 'PARENT' can be
* used for none. * used for none.
* @return {string}
*/ */
navigateToChange(change, opt_patchNum, opt_basePatchNum) { navigateToChange(change, opt_patchNum, opt_basePatchNum) {
this._navigate(this.getUrlForChange(change, opt_patchNum, this._navigate(this.getUrlForChange(change, opt_patchNum,
@@ -203,8 +206,8 @@ limitations under the License.
}, },
/** /**
* @param {!Object} change The change object. * @param {{ _number: number, project: string }} change The change object.
* @param {!string} path The file path. * @param {string} path The file path.
* @param {number=} opt_patchNum * @param {number=} opt_patchNum
* @param {number|string=} opt_basePatchNum The string 'PARENT' can be * @param {number|string=} opt_basePatchNum The string 'PARENT' can be
* used for none. * used for none.
@@ -247,7 +250,7 @@ limitations under the License.
/** /**
* @param {!Object} change The change object. * @param {!Object} change The change object.
* @param {!string} path The file path. * @param {string} path The file path.
* @param {number=} opt_patchNum * @param {number=} opt_patchNum
* @param {number|string=} opt_basePatchNum The string 'PARENT' can be * @param {number|string=} opt_basePatchNum The string 'PARENT' can be
* used for none. * used for none.
@@ -270,7 +273,7 @@ limitations under the License.
/** /**
* Navigate to an arbitrary relative URL. * Navigate to an arbitrary relative URL.
* @param {!string} relativeUrl * @param {string} relativeUrl
*/ */
navigateToRelativeUrl(relativeUrl) { navigateToRelativeUrl(relativeUrl) {
if (!relativeUrl.startsWith('/')) { if (!relativeUrl.startsWith('/')) {

View File

@@ -20,9 +20,13 @@
is: 'gr-comment-api', is: 'gr-comment-api',
properties: { properties: {
/** @type {number} */
_changeNum: Number, _changeNum: Number,
/** @type {!Object|undefined} */
_comments: Object, _comments: Object,
/** @type {!Object|undefined} */
_drafts: Object, _drafts: Object,
/** @type {!Object|undefined} */
_robotComments: Object, _robotComments: Object,
}, },
@@ -35,7 +39,7 @@
* number. The returned promise resolves when the comments have loaded, but * number. The returned promise resolves when the comments have loaded, but
* does not yield the comment data. * does not yield the comment data.
* *
* @param {!number} changeNum * @param {number} changeNum
* @return {!Promise} * @return {!Promise}
*/ */
loadAll(changeNum) { loadAll(changeNum) {
@@ -91,7 +95,7 @@
* @param {!string} path * @param {!string} path
* @param {!Object} patchRange The patch-range object containing patchNum * @param {!Object} patchRange The patch-range object containing patchNum
* and basePatchNum properties to represent the range. * and basePatchNum properties to represent the range.
* @param {Object} opt_projectConfig Optional project config object to * @param {Object=} opt_projectConfig Optional project config object to
* include in the meta sub-object. * include in the meta sub-object.
* @return {Object} * @return {Object}
*/ */
@@ -160,7 +164,7 @@
* Whether the given comment should be included in the given patch range. * Whether the given comment should be included in the given patch range.
* @param {!Object} comment * @param {!Object} comment
* @param {!Object} range * @param {!Object} range
* @return {boolean} * @return {boolean|undefined}
*/ */
_isInPatchRange(comment, range) { _isInPatchRange(comment, range) {
return this._isInBaseOfPatchRange(comment, range) || return this._isInBaseOfPatchRange(comment, range) ||

View File

@@ -393,7 +393,7 @@ limitations under the License.
}, },
/** /**
* @return {Boolean} whether any of the lines in _groups are longer * @return {boolean} whether any of the lines in _groups are longer
* than SYNTAX_MAX_LINE_LENGTH. * than SYNTAX_MAX_LINE_LENGTH.
*/ */
_anyLineTooLong() { _anyLineTooLong() {

View File

@@ -153,12 +153,12 @@
/** /**
* Find line elements or line objects by a range of line numbers and a side. * Find line elements or line objects by a range of line numbers and a side.
* *
* @param {Number} start The first line number * @param {number} start The first line number
* @param {Number} end The last line number * @param {number} end The last line number
* @param {String} opt_side The side of the range. Either 'left' or 'right'. * @param {string} opt_side The side of the range. Either 'left' or 'right'.
* @param {Array<GrDiffLine>} out_lines The output list of line objects. Use * @param {!Array<GrDiffLine>} out_lines The output list of line objects. Use
* null if not desired. * null if not desired.
* @param {Array<HTMLElement>} out_elements The output list of line elements. * @param {!Array<HTMLElement>} out_elements The output list of line elements.
* Use null if not desired. * Use null if not desired.
*/ */
GrDiffBuilder.prototype.findLinesByRange = function(start, end, opt_side, GrDiffBuilder.prototype.findLinesByRange = function(start, end, opt_side,
@@ -443,7 +443,7 @@
/** /**
* Returns the text length after normalizing unicode and tabs. * Returns the text length after normalizing unicode and tabs.
* @return {Number} The normalized length of the text. * @return {number} The normalized length of the text.
*/ */
GrDiffBuilder.prototype._textLength = function(text, tabSize) { GrDiffBuilder.prototype._textLength = function(text, tabSize) {
text = text.replace(REGEX_ASTRAL_SYMBOL, '_'); text = text.replace(REGEX_ASTRAL_SYMBOL, '_');
@@ -536,9 +536,9 @@
* elements in place of tab characters. In each case tab elements are given * elements in place of tab characters. In each case tab elements are given
* the width needed to reach the next tab-stop. * the width needed to reach the next tab-stop.
* *
* @param {String} A line of text potentially containing tab characters. * @param {string} A line of text potentially containing tab characters.
* @param {Number} The width for tabs. * @param {number} The width for tabs.
* @return {String} An HTML string potentially containing tab elements. * @return {string} An HTML string potentially containing tab elements.
*/ */
GrDiffBuilder.prototype._addTabWrappers = function(line, tabSize) { GrDiffBuilder.prototype._addTabWrappers = function(line, tabSize) {
if (!line.length) { return ''; } if (!line.length) { return ''; }
@@ -600,7 +600,7 @@
* Finds the next DIV.contentText element following the given element, and on * Finds the next DIV.contentText element following the given element, and on
* the same side. Will only search within a group. * the same side. Will only search within a group.
* @param {HTMLElement} content * @param {HTMLElement} content
* @param {String} side Either 'left' or 'right' * @param {string} side Either 'left' or 'right'
* @return {HTMLElement} * @return {HTMLElement}
*/ */
GrDiffBuilder.prototype._getNextContentOnSide = function(content, side) { GrDiffBuilder.prototype._getNextContentOnSide = function(content, side) {
@@ -610,8 +610,8 @@
/** /**
* Determines whether the given group is either totally an addition or totally * Determines whether the given group is either totally an addition or totally
* a removal. * a removal.
* @param {GrDiffGroup} group * @param {!Object} group (GrDiffGroup)
* @return {Boolean} * @return {boolean}
*/ */
GrDiffBuilder.prototype._isTotal = function(group) { GrDiffBuilder.prototype._isTotal = function(group) {
return group.type === GrDiffGroup.Type.DELTA && return group.type === GrDiffGroup.Type.DELTA &&

View File

@@ -213,6 +213,9 @@
return !!comment.__draft; return !!comment.__draft;
}, },
/**
* @param {boolean=} opt_quote
*/
_processCommentReply(opt_quote) { _processCommentReply(opt_quote) {
const comment = this._lastComment; const comment = this._lastComment;
let quoteStr; let quoteStr;
@@ -273,6 +276,10 @@
return d; return d;
}, },
/**
* @param {number=} opt_lineNum
* @param {!Object=} opt_range
*/
_newDraft(opt_lineNum, opt_range) { _newDraft(opt_lineNum, opt_range) {
const d = { const d = {
__draft: true, __draft: true,

View File

@@ -53,6 +53,7 @@
properties: { properties: {
changeNum: String, changeNum: String,
/** @type {?} */
comment: { comment: {
type: Object, type: Object,
notify: true, notify: true,
@@ -88,6 +89,7 @@
value: true, value: true,
observer: '_toggleCollapseClass', observer: '_toggleCollapseClass',
}, },
/** @type {?} */
projectConfig: Object, projectConfig: Object,
robotButtonDisabled: Boolean, robotButtonDisabled: Boolean,
_isAdmin: { _isAdmin: {
@@ -215,6 +217,11 @@
} }
}, },
/**
* @param {!Object=} opt_mixin
*
* @return {!Object}
*/
_getEventPayload(opt_mixin) { _getEventPayload(opt_mixin) {
return Object.assign({}, opt_mixin, { return Object.assign({}, opt_mixin, {
comment: this.comment, comment: this.comment,

View File

@@ -43,6 +43,7 @@
type: String, type: String,
value: DiffSides.RIGHT, value: DiffSides.RIGHT,
}, },
/** @type {!HTMLElement|undefined} */
diffRow: { diffRow: {
type: Object, type: Object,
notify: true, notify: true,
@@ -61,6 +62,8 @@
* If set, the cursor will attempt to move to the line number (instead of * If set, the cursor will attempt to move to the line number (instead of
* the first chunk) the next time the diff renders. It is set back to null * the first chunk) the next time the diff renders. It is set back to null
* when used. * when used.
*
* @type (?number)
*/ */
initialLineNumber: { initialLineNumber: {
type: Number, type: Number,
@@ -147,6 +150,11 @@
this._fixSide(); this._fixSide();
}, },
/**
* @param {number} number
* @param {string} side
* @param {string=} opt_path
*/
moveToLineNumber(number, side, opt_path) { moveToLineNumber(number, side, opt_path) {
const row = this._findRowByNumberAndFile(number, side, opt_path); const row = this._findRowByNumberAndFile(number, side, opt_path);
if (row) { if (row) {
@@ -157,7 +165,7 @@
/** /**
* Get the line number element targeted by the cursor row and side. * Get the line number element targeted by the cursor row and side.
* @return {DOMElement} * @return {?Element|undefined}
*/ */
getTargetLineElement() { getTargetLineElement() {
let lineElSelector = '.lineNum'; let lineElSelector = '.lineNum';
@@ -221,7 +229,7 @@
* Get a short address for the location of the cursor. Such as '123' for * Get a short address for the location of the cursor. Such as '123' for
* line 123 of the revision, or 'b321' for line 321 of the base patch. * line 123 of the revision, or 'b321' for line 321 of the base patch.
* Returns an empty string if an address is not available. * Returns an empty string if an address is not available.
* @return {String} * @return {string}
*/ */
getAddress() { getAddress() {
if (!this.diffRow) { return ''; } if (!this.diffRow) { return ''; }

View File

@@ -28,8 +28,8 @@
/** /**
* The DOM API textContent.length calculation is broken when the text * The DOM API textContent.length calculation is broken when the text
* contains Unicode. See https://mathiasbynens.be/notes/javascript-unicode . * contains Unicode. See https://mathiasbynens.be/notes/javascript-unicode .
* @param {Text} A text node. * @param {!Text} node text node.
* @return {Number} The length of the text. * @return {number} The length of the text.
*/ */
getLength(node) { getLength(node) {
return this.getStringLength(node.textContent); return this.getStringLength(node.textContent);

View File

@@ -20,6 +20,11 @@
properties: { properties: {
comments: Object, comments: Object,
loggedIn: Boolean, loggedIn: Boolean,
/**
* querySelector can return null, so needs to be nullable.
*
* @type {?HTMLElement}
* */
_cachedDiffBuilder: Object, _cachedDiffBuilder: Object,
isAttached: Boolean, isAttached: Boolean,
}, },
@@ -99,7 +104,7 @@
* Merges multiple ranges, accounts for triple click, accounts for * Merges multiple ranges, accounts for triple click, accounts for
* syntax highligh, convert native DOM Range objects to Gerrit concepts * syntax highligh, convert native DOM Range objects to Gerrit concepts
* (line, side, etc). * (line, side, etc).
* @return {{ * @return {({
* start: { * start: {
* node: Node, * node: Node,
* side: string, * side: string,
@@ -112,7 +117,7 @@
* line: Number, * line: Number,
* column: Number * column: Number
* } * }
* }} * })|null|!Object}
*/ */
_getNormalizedRange() { _getNormalizedRange() {
const selection = window.getSelection(); const selection = window.getSelection();
@@ -134,6 +139,7 @@
/** /**
* Normalize a specific DOM Range. * Normalize a specific DOM Range.
* @return {!Object} fixed normalized range
*/ */
_normalizeRange(domRange) { _normalizeRange(domRange) {
const range = GrRangeNormalizer.normalize(domRange); const range = GrRangeNormalizer.normalize(domRange);
@@ -195,12 +201,12 @@
* *
* @param {Node} node td.content child * @param {Node} node td.content child
* @param {number} offset offset within node * @param {number} offset offset within node
* @return {{ * @return {({
* node: Node, * node: Node,
* side: string, * side: string,
* line: Number, * line: Number,
* column: Number * column: Number
* }} * }|undefined)}
*/ */
_normalizeSelectionSide(node, offset) { _normalizeSelectionSide(node, offset) {
let column; let column;
@@ -251,6 +257,7 @@
return; return;
} }
const domRange = window.getSelection().getRangeAt(0); const domRange = window.getSelection().getRangeAt(0);
/** @type {?} */
const start = normalizedRange.start; const start = normalizedRange.start;
if (!start) { if (!start) {
return; return;
@@ -280,7 +287,9 @@
if (start.line === end.line) { if (start.line === end.line) {
actionBox.placeAbove(domRange); actionBox.placeAbove(domRange);
} else if (start.node instanceof Text) { } else if (start.node instanceof Text) {
actionBox.placeAbove(start.node.splitText(start.column)); if (start.column) {
actionBox.placeAbove(start.node.splitText(start.column));
}
start.node.parentElement.normalize(); // Undo splitText from above. start.node.parentElement.normalize(); // Undo splitText from above.
} else if (start.node.classList.contains('content') && } else if (start.node.classList.contains('content') &&
start.node.firstChild) { start.node.firstChild) {
@@ -325,7 +334,7 @@
* Traverse Element from right to left, call callback for each node. * Traverse Element from right to left, call callback for each node.
* Stops if callback returns true. * Stops if callback returns true.
* *
* @param {!Node} startNode * @param {!Element} startNode
* @param {function(Node):boolean} callback * @param {function(Node):boolean} callback
* @param {Object=} opt_flags If flags.left is true, traverse left. * @param {Object=} opt_flags If flags.left is true, traverse left.
*/ */
@@ -350,7 +359,7 @@
* Get length of a node. If the node is a content node, then only give the * Get length of a node. If the node is a content node, then only give the
* length of its .contentText child. * length of its .contentText child.
* *
* @param {!Node} node * @param {?Element} node this is sometimes passed as null.
* @return {number} * @return {number}
*/ */
_getLength(node) { _getLength(node) {

View File

@@ -27,8 +27,8 @@
* highlighting, the containers are remapped to the .contentText divs that * highlighting, the containers are remapped to the .contentText divs that
* contain the entire line of code. * contain the entire line of code.
* *
* @param {Object} range - the standard DOM selector range. * @param {!Object} range - the standard DOM selector range.
* @return {Object} A modified version of the range that correctly accounts * @return {!Object} A modified version of the range that correctly accounts
* for syntax highlighting. * for syntax highlighting.
*/ */
normalize(range) { normalize(range) {
@@ -94,8 +94,8 @@
/** /**
* The DOM API textContent.length calculation is broken when the text * The DOM API textContent.length calculation is broken when the text
* contains Unicode. See https://mathiasbynens.be/notes/javascript-unicode . * contains Unicode. See https://mathiasbynens.be/notes/javascript-unicode .
* @param {Text} A text node. * @param {text} node A text node.
* @return {Number} The length of the text. * @return {number} The length of the text.
*/ */
_getLength(node) { _getLength(node) {
return node.textContent.replace(REGEX_ASTRAL_SYMBOL, '_').length; return node.textContent.replace(REGEX_ASTRAL_SYMBOL, '_').length;

View File

@@ -32,6 +32,7 @@
reflectToAttribute: true, reflectToAttribute: true,
}, },
/** @type {?} */
_newPrefs: Object, _newPrefs: Object,
_newLocalPrefs: Object, _newLocalPrefs: Object,
}, },

View File

@@ -77,6 +77,7 @@
value: 64, value: 64,
}, },
/** @type {number|undefined} */
_nextStepHandle: Number, _nextStepHandle: Number,
_isScrolling: Boolean, _isScrolling: Boolean,
}, },
@@ -225,14 +226,14 @@
/** /**
* Take rows of a shared diff section and produce an array of corresponding * Take rows of a shared diff section and produce an array of corresponding
* (potentially collapsed) groups. * (potentially collapsed) groups.
* @param {Array<String>} rows * @param {!Array<string>} rows
* @param {Number} context * @param {number} context
* @param {Number} startLineNumLeft * @param {number} startLineNumLeft
* @param {Number} startLineNumRight * @param {number} startLineNumRight
* @param {String} opt_sectionEnd String representing whether this is the * @param {?string=} opt_sectionEnd String representing whether this is the
* first section or the last section or neither. Use the values 'first', * first section or the last section or neither. Use the values 'first',
* 'last' and null respectively. * 'last' and null respectively.
* @return {Array<GrDiffGroup>} * @return {!Array<!Object>} Array of GrDiffGroup
*/ */
_sharedGroupsFromRows(rows, context, startLineNumLeft, _sharedGroupsFromRows(rows, context, startLineNumLeft,
startLineNumRight, opt_sectionEnd) { startLineNumRight, opt_sectionEnd) {
@@ -288,11 +289,11 @@
/** /**
* Take the rows of a delta diff section and produce the corresponding * Take the rows of a delta diff section and produce the corresponding
* group. * group.
* @param {Array<String>} rowsAdded * @param {!Array<string>} rowsAdded
* @param {Array<String>} rowsRemoved * @param {!Array<string>} rowsRemoved
* @param {Number} startLineNumLeft * @param {number} startLineNumLeft
* @param {Number} startLineNumRight * @param {number} startLineNumRight
* @return {GrDiffGroup} * @return {!Object} (Gr-Diff-Group)
*/ */
_deltaGroupFromRows(rowsAdded, rowsRemoved, startLineNumLeft, _deltaGroupFromRows(rowsAdded, rowsRemoved, startLineNumLeft,
startLineNumRight, highlights) { startLineNumRight, highlights) {
@@ -309,7 +310,7 @@
}, },
/** /**
* @return {Array<GrDiffLine>} * @return {!Array<!Object>} Array of GrDiffLines
*/ */
_deltaLinesFromRows(lineType, rows, startLineNum, _deltaLinesFromRows(lineType, rows, startLineNum,
opt_highlights) { opt_highlights) {
@@ -348,8 +349,8 @@
* In order to show comments out of the bounds of the selected context, * In order to show comments out of the bounds of the selected context,
* treat them as separate chunks within the model so that the content (and * treat them as separate chunks within the model so that the content (and
* context surrounding it) renders correctly. * context surrounding it) renders correctly.
* @param {Object} content The diff content object. * @param {?} content The diff content object. (has to be iterable)
* @return {Object} A new diff content object with regions split up. * @return {!Object} A new diff content object with regions split up.
*/ */
_splitCommonGroupsWithComments(content) { _splitCommonGroupsWithComments(content) {
const result = []; const result = [];
@@ -492,7 +493,7 @@
* If a group is an addition or a removal, break it down into smaller groups * If a group is an addition or a removal, break it down into smaller groups
* of that type using the MAX_GROUP_SIZE. If the group is a shared section * of that type using the MAX_GROUP_SIZE. If the group is a shared section
* or a delta it is returned as the single element of the result array. * or a delta it is returned as the single element of the result array.
* @param {!Object} A raw chunk from a diff response. * @param {!Object} group A raw chunk from a diff response.
* @return {!Array<!Array<!Object>>} * @return {!Array<!Array<!Object>>}
*/ */
_breakdownGroup(group) { _breakdownGroup(group) {

View File

@@ -31,6 +31,7 @@
properties: { properties: {
diff: Object, diff: Object,
/** @type {?Object} */
_cachedDiffBuilder: Object, _cachedDiffBuilder: Object,
_linesCache: { _linesCache: {
type: Object, type: Object,
@@ -144,14 +145,14 @@
* true, it returns only the text of comments within the selection. * true, it returns only the text of comments within the selection.
* Otherwise it returns the text of the selected diff region. * Otherwise it returns the text of the selected diff region.
* *
* @param {!string} The side that is selected. * @param {!string} side The side that is selected.
* @param {boolean} Whether or not a comment is selected. * @param {boolean} commentSelected Whether or not a comment is selected.
* @return {string} The selected text. * @return {string} The selected text.
*/ */
_getSelectedText(side, commentSelected) { _getSelectedText(side, commentSelected) {
const sel = window.getSelection(); const sel = window.getSelection();
if (sel.rangeCount != 1) { if (sel.rangeCount != 1) {
return; // No multi-select support yet. return ''; // No multi-select support yet.
} }
if (commentSelected) { if (commentSelected) {
return this._getCommentLines(sel, side); return this._getCommentLines(sel, side);
@@ -170,10 +171,10 @@
/** /**
* Query the diff object for the selected lines. * Query the diff object for the selected lines.
* *
* @param {int} startLineNum * @param {number} startLineNum
* @param {int} startOffset * @param {number} startOffset
* @param {int} endLineNum * @param {number} endLineNum
* @param {int} endOffset * @param {number} endOffset
* @param {!string} side The side that is currently selected. * @param {!string} side The side that is currently selected.
* @return {string} The selected diff text. * @return {string} The selected diff text.
*/ */
@@ -192,7 +193,7 @@
* Query the diff object for the lines from a particular side. * Query the diff object for the lines from a particular side.
* *
* @param {!string} side The side that is currently selected. * @param {!string} side The side that is currently selected.
* @return {Array.string} An array of strings indexed by line number. * @return {!Array<string>} An array of strings indexed by line number.
*/ */
_getDiffLines(side) { _getDiffLines(side) {
if (this._linesCache[side]) { if (this._linesCache[side]) {
@@ -254,9 +255,9 @@
* of the text content within that selection. * of the text content within that selection.
* Using a domNode that isn't in the selection returns an empty string. * Using a domNode that isn't in the selection returns an empty string.
* *
* @param {Element} domNode The root DOM node. * @param {!Node} domNode The root DOM node.
* @param {Selection} sel The selection. * @param {!Selection} sel The selection.
* @param {Range} range The normalized selection range. * @param {!Range} range The normalized selection range.
* @return {string} The text within the selection. * @return {string} The text within the selection.
*/ */
_getTextContentForRange(domNode, sel, range) { _getTextContentForRange(domNode, sel, range) {

View File

@@ -55,6 +55,9 @@
type: Object, type: Object,
value() { return document.body; }, value() { return document.body; },
}, },
/**
* @type {{ diffMode: (string|undefined) }}
*/
changeViewState: { changeViewState: {
type: Object, type: Object,
notify: true, notify: true,
@@ -63,6 +66,13 @@
}, },
_patchRange: Object, _patchRange: Object,
/**
* @type {{
* subject: string,
* project: string,
* revisions: string,
* }}
*/
_change: Object, _change: Object,
_changeNum: String, _changeNum: String,
_diff: Object, _diff: Object,
@@ -400,7 +410,7 @@
/** /**
* @param {?string} path The path of the current file being shown. * @param {?string} path The path of the current file being shown.
* @param {Array.<string>} fileList The list of files in this change and * @param {!Array<string>} fileList The list of files in this change and
* patch range. * patch range.
* @param {number} direction Either 1 (next file) or -1 (prev file). * @param {number} direction Either 1 (next file) or -1 (prev file).
* @param {(number|boolean)} opt_noUp Whether to return to the change view * @param {(number|boolean)} opt_noUp Whether to return to the change view
@@ -433,12 +443,12 @@
* * null - When no navigation is possible for the given direction. * * null - When no navigation is possible for the given direction.
* *
* @param {?string} path The path of the current file being shown. * @param {?string} path The path of the current file being shown.
* @param {Array.<string>} fileList The list of files in this change and * @param {!Array<string>} fileList The list of files in this change and
* patch range. * patch range.
* @param {number} direction Either 1 (next file) or -1 (prev file). * @param {number} direction Either 1 (next file) or -1 (prev file).
* @param {(number|boolean)} opt_noUp Whether to return to the change view * @param {?number|boolean=} opt_noUp Whether to return to the change view
* when advancing the file goes outside the bounds of fileList. * when advancing the file goes outside the bounds of fileList.
* @return {Object} * @return {?Object}
*/ */
_getNavLinkPath(path, fileList, direction, opt_noUp) { _getNavLinkPath(path, fileList, direction, opt_noUp) {
if (!path || fileList.length === 0) { return null; } if (!path || fileList.length === 0) { return null; }
@@ -589,6 +599,10 @@
* When the latest patch of the change is selected (and there is no base * When the latest patch of the change is selected (and there is no base
* patch) then the patch range need not appear in the URL. Return a patch * patch) then the patch range need not appear in the URL. Return a patch
* range object with undefined values when a range is not needed. * range object with undefined values when a range is not needed.
*
* @param {!Object} patchRange
* @param {!Object} revisions
* @return {!Object}
*/ */
_getChangeUrlRange(patchRange, revisions) { _getChangeUrlRange(patchRange, revisions) {
let patchNum = undefined; let patchNum = undefined;
@@ -702,7 +716,7 @@
* *
* Use side-by-side if the user is not logged in. * Use side-by-side if the user is not logged in.
* *
* @return {String} * @return {string}
*/ */
_getDiffViewMode() { _getDiffViewMode() {
if (this.changeViewState.diffMode) { if (this.changeViewState.diffMode) {
@@ -721,7 +735,7 @@
_onLineSelected(e, detail) { _onLineSelected(e, detail) {
this.$.cursor.moveToLineNumber(detail.number, detail.side); this.$.cursor.moveToLineNumber(detail.number, detail.side);
history.replaceState(null, null, '#' + this.$.cursor.getAddress()); history.replaceState(null, '', '#' + this.$.cursor.getAddress());
}, },
_computeDownloadLink(changeNum, patchRange, path) { _computeDownloadLink(changeNum, patchRange, path) {

View File

@@ -106,7 +106,9 @@
type: String, type: String,
value: '', value: '',
}, },
/** @type {?Object} */
_baseImage: Object, _baseImage: Object,
/** @type {?Object} */
_revisionImage: Object, _revisionImage: Object,
/** /**
@@ -114,6 +116,8 @@
* been bypassed. If the value is null, then the safety has not been * been bypassed. If the value is null, then the safety has not been
* bypassed. If the value is a number, then that number represents the * bypassed. If the value is a number, then that number represents the
* context preference to use when rendering the bypassed diff. * context preference to use when rendering the bypassed diff.
*
* @type (number|null)
*/ */
_safetyBypass: { _safetyBypass: {
type: Number, type: Number,
@@ -147,6 +151,7 @@
} }
}, },
/** @return {!Promise} */
reload() { reload() {
this.$.diffBuilder.cancel(); this.$.diffBuilder.cancel();
this._safetyBypass = null; this._safetyBypass = null;
@@ -168,6 +173,7 @@
}); });
}, },
/** @return {!Array<!HTMLElement>} */
getCursorStops() { getCursorStops() {
if (this.hidden && this.noAutoRender) { if (this.hidden && this.noAutoRender) {
return []; return [];
@@ -176,6 +182,7 @@
return Polymer.dom(this.root).querySelectorAll('.diff-row'); return Polymer.dom(this.root).querySelectorAll('.diff-row');
}, },
/** @return {boolean} */
isRangeSelected() { isRangeSelected() {
return this.$.highlights.isRangeSelected(); return this.$.highlights.isRangeSelected();
}, },
@@ -184,15 +191,18 @@
this.toggleClass('no-left'); this.toggleClass('no-left');
}, },
/** @return {boolean}} */
_canRender() { _canRender() {
return this.changeNum && this.patchRange && this.path && return !!this.changeNum && !!this.patchRange && !!this.path &&
!this.noAutoRender; !this.noAutoRender;
}, },
/** @return {!Array<!HTMLElement>} */
_getCommentThreads() { _getCommentThreads() {
return Polymer.dom(this.root).querySelectorAll('gr-diff-comment-thread'); return Polymer.dom(this.root).querySelectorAll('gr-diff-comment-thread');
}, },
/** @return {string} */
_computeContainerClass(loggedIn, viewMode, displayLine) { _computeContainerClass(loggedIn, viewMode, displayLine) {
const classes = ['diffContainer']; const classes = ['diffContainer'];
switch (viewMode) { switch (viewMode) {
@@ -263,7 +273,7 @@
const side = e.detail.side; const side = e.detail.side;
const lineNum = range.endLine; const lineNum = range.endLine;
const lineEl = this.$.diffBuilder.getLineElByNumber(lineNum, side); const lineEl = this.$.diffBuilder.getLineElByNumber(lineNum, side);
this._isValidElForComment(el).then(valid => { this._isValidElForComment(lineEl).then(valid => {
if (!valid) { return; } if (!valid) { return; }
this._createComment(lineEl, lineNum, side, range); this._createComment(lineEl, lineNum, side, range);
@@ -288,6 +298,12 @@
}); });
}, },
/**
* @param {!Object} lineEl
* @param {number=} opt_lineNum
* @param {string=} opt_side
* @param {!Object=} opt_range
*/
_createComment(lineEl, opt_lineNum, opt_side, opt_range) { _createComment(lineEl, opt_lineNum, opt_side, opt_range) {
const contentText = this.$.diffBuilder.getContentByLineEl(lineEl); const contentText = this.$.diffBuilder.getContentByLineEl(lineEl);
const contentEl = contentText.parentElement; const contentEl = contentText.parentElement;
@@ -309,14 +325,21 @@
return contentEl.querySelector('gr-diff-comment-thread-group'); return contentEl.querySelector('gr-diff-comment-thread-group');
}, },
/**
* @param {!Object} contentEl
* @param {number} patchNum
* @param {string} commentSide
* @param {boolean} isOnParent
* @param {!Object=} opt_range
*/
_getOrCreateThreadAtLineRange(contentEl, patchNum, commentSide, _getOrCreateThreadAtLineRange(contentEl, patchNum, commentSide,
isOnParent, range) { isOnParent, opt_range) {
const rangeToCheck = range ? const rangeToCheck = opt_range ?
'range-' + 'range-' +
range.startLine + '-' + opt_range.startLine + '-' +
range.startChar + '-' + opt_range.startChar + '-' +
range.endLine + '-' + opt_range.endLine + '-' +
range.endChar + '-' + opt_range.endChar + '-' +
commentSide : 'line-' + commentSide; commentSide : 'line-' + commentSide;
// Check if thread group exists. // Check if thread group exists.
@@ -338,6 +361,7 @@
return threadEl; return threadEl;
}, },
/** @return {number} */
_getPatchNumByLineAndContent(lineEl, contentEl) { _getPatchNumByLineAndContent(lineEl, contentEl) {
let patchNum = this.patchRange.patchNum; let patchNum = this.patchRange.patchNum;
if ((lineEl.classList.contains(DiffSide.LEFT) || if ((lineEl.classList.contains(DiffSide.LEFT) ||
@@ -348,6 +372,7 @@
return patchNum; return patchNum;
}, },
/** @return {boolean} */
_getIsParentCommentByLineAndContent(lineEl, contentEl) { _getIsParentCommentByLineAndContent(lineEl, contentEl) {
let isOnParent = false; let isOnParent = false;
if ((lineEl.classList.contains(DiffSide.LEFT) || if ((lineEl.classList.contains(DiffSide.LEFT) ||
@@ -358,6 +383,7 @@
return isOnParent; return isOnParent;
}, },
/** @return {string} */
_getCommentSideByLineAndContent(lineEl, contentEl) { _getCommentSideByLineAndContent(lineEl, contentEl) {
let side = 'right'; let side = 'right';
if (lineEl.classList.contains(DiffSide.LEFT) || if (lineEl.classList.contains(DiffSide.LEFT) ||
@@ -374,7 +400,7 @@
_handleCommentDiscard(e) { _handleCommentDiscard(e) {
const comment = e.detail.comment; const comment = e.detail.comment;
this._removeComment(comment, e.detail.patchNum); this._removeComment(comment);
}, },
_removeComment(comment) { _removeComment(comment) {
@@ -389,6 +415,12 @@
this.set(['comments', side, idx], comment); this.set(['comments', side, idx], comment);
}, },
/**
* Closure annotation for Polymer.prototype.push is off. Submitted PR:
* https://github.com/Polymer/polymer/pull/4776
* but for not supressing annotations.
*
* @suppress {checkTypes} */
_handleCommentUpdate(e) { _handleCommentUpdate(e) {
const comment = e.detail.comment; const comment = e.detail.comment;
const side = e.detail.comment.__commentSide; const side = e.detail.comment.__commentSide;
@@ -413,6 +445,7 @@
} }
}, },
/** @return {number} */
_findCommentIndex(comment, side) { _findCommentIndex(comment, side) {
if (!comment.id || !this.comments[side]) { if (!comment.id || !this.comments[side]) {
return -1; return -1;
@@ -422,6 +455,7 @@
}); });
}, },
/** @return {number} */
_findDraftIndex(comment, side) { _findDraftIndex(comment, side) {
if (!comment.__draftID || !this.comments[side]) { if (!comment.__draftID || !this.comments[side]) {
return -1; return -1;
@@ -517,6 +551,7 @@
this.fire('page-error', {response}); this.fire('page-error', {response});
}, },
/** @return {!Promise<!Object>} */
_getDiff() { _getDiff() {
return this.$.restAPI.getDiff( return this.$.restAPI.getDiff(
this.changeNum, this.changeNum,
@@ -532,10 +567,12 @@
}); });
}, },
/** @return {!Promise} */
_getLoggedIn() { _getLoggedIn() {
return this.$.restAPI.getLoggedIn(); return this.$.restAPI.getLoggedIn();
}, },
/** @return {boolean} */
_computeIsImageDiff() { _computeIsImageDiff() {
if (!this._diff) { return false; } if (!this._diff) { return false; }
@@ -547,6 +584,7 @@
return this._diff.binary && (isA || isB); return this._diff.binary && (isA || isB);
}, },
/** @return {!Promise} */
_loadDiffAssets() { _loadDiffAssets() {
if (this.isImageDiff) { if (this.isImageDiff) {
return this._getImages().then(images => { return this._getImages().then(images => {
@@ -560,6 +598,7 @@
} }
}, },
/** @return {!Promise} */
_getImages() { _getImages() {
return this.$.restAPI.getImagesForDiff(this.changeNum, this._diff, return this.$.restAPI.getImagesForDiff(this.changeNum, this._diff,
this.patchRange); this.patchRange);
@@ -572,6 +611,7 @@
} }
}, },
/** @return {!Array} */
_computeDiffHeaderItems(diffInfoRecord) { _computeDiffHeaderItems(diffInfoRecord) {
const diffInfo = diffInfoRecord.base; const diffInfo = diffInfoRecord.base;
if (!diffInfo || !diffInfo.diff_header || diffInfo.binary) { return []; } if (!diffInfo || !diffInfo.diff_header || diffInfo.binary) { return []; }
@@ -583,6 +623,7 @@
}); });
}, },
/** @return {boolean} */
_computeDiffHeaderHidden(items) { _computeDiffHeaderHidden(items) {
return items.length === 0; return items.length === 0;
}, },
@@ -591,7 +632,7 @@
* The number of lines in the diff. For delta chunks that are different * The number of lines in the diff. For delta chunks that are different
* sizes on the left and the right, the longer side is used. * sizes on the left and the right, the longer side is used.
* @param {!Object} diff * @param {!Object} diff
* @return {Number} * @return {number}
*/ */
_diffLength(diff) { _diffLength(diff) {
return diff.content.reduce((sum, sec) => { return diff.content.reduce((sum, sec) => {
@@ -616,6 +657,7 @@
this._renderDiffTable(); this._renderDiffTable();
}, },
/** @return {string} */
_computeWarningClass(showWarning) { _computeWarningClass(showWarning) {
return showWarning ? 'warn' : ''; return showWarning ? 'warn' : '';
}, },

View File

@@ -23,6 +23,7 @@
properties: { properties: {
availablePatches: Array, availablePatches: Array,
changeNum: String, changeNum: String,
/** @type {{ meta_a: !Array, meta_b: !Array}} */
filesWeblinks: Object, filesWeblinks: Object,
path: String, path: String,
patchRange: { patchRange: {

View File

@@ -43,9 +43,9 @@
/** /**
* Layer method to add annotations to a line. * Layer method to add annotations to a line.
* @param {HTMLElement} el The DIV.contentText element to apply the * @param {!HTMLElement} el The DIV.contentText element to apply the
* annotation to. * annotation to.
* @param {GrDiffLine} line The line object. * @param {!Object} line The line object. (GrDiffLine)
*/ */
annotate(el, line) { annotate(el, line) {
let ranges = []; let ranges = [];
@@ -79,9 +79,9 @@
/** /**
* Notify Layer listeners of changes to annotations. * Notify Layer listeners of changes to annotations.
* @param {Number} start The line where the update starts. * @param {number} start The line where the update starts.
* @param {Number} end The line where the update ends. * @param {number} end The line where the update ends.
* @param {String} side The side of the update. ('left' or 'right') * @param {string} side The side of the update. ('left' or 'right')
*/ */
_notifyUpdateRange(start, end, side) { _notifyUpdateRange(start, end, side) {
for (const listener of this._listeners) { for (const listener of this._listeners) {
@@ -133,8 +133,9 @@
* Take a list of comments and return a sparse list mapping line numbers to * Take a list of comments and return a sparse list mapping line numbers to
* partial ranges. Uses an end-character-index of -1 to indicate the end of * partial ranges. Uses an end-character-index of -1 to indicate the end of
* the line. * the line.
* @param {Array<Object>} commentList The list of comments. * @param {?} commentList The list of comments.
* @return {Object} The sparse list. * Getting this param to match closure requirements caused problems.
* @return {!Object} The sparse list.
*/ */
_computeCommentMap(commentList) { _computeCommentMap(commentList) {
const result = {}; const result = {};

View File

@@ -114,6 +114,7 @@
type: Array, type: Array,
value() { return []; }, value() { return []; },
}, },
/** @type {?number} */
_processHandle: Number, _processHandle: Number,
_hljs: Object, _hljs: Object,
}, },
@@ -126,7 +127,7 @@
* Annotation layer method to add syntax annotations to the given element * Annotation layer method to add syntax annotations to the given element
* for the given line. * for the given line.
* @param {!HTMLElement} el * @param {!HTMLElement} el
* @param {!GrDiffLine} line * @param {!Object} line (GrDiffLine)
*/ */
annotate(el, line) { annotate(el, line) {
if (!this.enabled) { return; } if (!this.enabled) { return; }

View File

@@ -31,6 +31,9 @@
*/ */
properties: { properties: {
/**
* @type {{ query: string, view: string }}
*/
params: Object, params: Object,
keyEventTarget: { keyEventTarget: {
type: Object, type: Object,
@@ -41,6 +44,9 @@
type: Object, type: Object,
observer: '_accountChanged', observer: '_accountChanged',
}, },
/**
* @type {{ plugin: Object }}
*/
_serverConfig: Object, _serverConfig: Object,
_version: String, _version: String,
_showChangeListView: Boolean, _showChangeListView: Boolean,
@@ -50,7 +56,9 @@
_showSettingsView: Boolean, _showSettingsView: Boolean,
_showAdminView: Boolean, _showAdminView: Boolean,
_showCLAView: Boolean, _showCLAView: Boolean,
/** @type {?} */
_viewState: Object, _viewState: Object,
/** @type {?} */
_lastError: Object, _lastError: Object,
_lastSearchPage: String, _lastSearchPage: String,
_path: String, _path: String,

View File

@@ -42,6 +42,12 @@
this._importHtmlPlugins(htmlPlugins); this._importHtmlPlugins(htmlPlugins);
}, },
/**
* @suppress {checkTypes}
* States that it expects no more than 3 parameters, but that's not true.
* @todo (beckysiegel) check Polymer annotations and submit change.
*/
_importHtmlPlugins(plugins) { _importHtmlPlugins(plugins) {
for (const url of plugins) { for (const url of plugins) {
this.importHref( this.importHref(

View File

@@ -51,6 +51,7 @@
type: Boolean, type: Boolean,
value: false, value: false,
}, },
/** @type {?} */
_account: Object, _account: Object,
_serverConfig: Object, _serverConfig: Object,
}, },

View File

@@ -29,6 +29,7 @@
type: Array, type: Array,
value() { return []; }, value() { return []; },
}, },
/** @type {?string} */
_newPreferred: { _newPreferred: {
type: String, type: String,
value: null, value: null,
@@ -61,7 +62,7 @@
}, },
_handleDeleteButton(e) { _handleDeleteButton(e) {
const index = parseInt(e.target.getAttribute('data-index')); const index = parseInt(e.target.getAttribute('data-index'), 10);
const email = this._emails[index]; const email = this._emails[index];
this.push('_emailsToRemove', email); this.push('_emailsToRemove', email);
this.splice('_emails', index, 1); this.splice('_emails', index, 1);

View File

@@ -50,7 +50,7 @@
}, },
_generatedPasswordOverlayClosed() { _generatedPasswordOverlayClosed() {
this._generatedPassword = null; this._generatedPassword = '';
}, },
}); });
})(); })();

View File

@@ -30,6 +30,7 @@
*/ */
properties: { properties: {
/** @type {?} */
_account: Object, _account: Object,
_saving: Boolean, _saving: Boolean,
}, },

View File

@@ -56,8 +56,10 @@
}, },
_accountNameMutable: Boolean, _accountNameMutable: Boolean,
_accountInfoChanged: Boolean, _accountInfoChanged: Boolean,
/** @type {?} */
_diffPrefs: Object, _diffPrefs: Object,
_changeTableColumnsNotDisplayed: Array, _changeTableColumnsNotDisplayed: Array,
/** @type {?} */
_localPrefs: { _localPrefs: {
type: Object, type: Object,
value() { return {}; }, value() { return {}; },
@@ -107,8 +109,11 @@
type: String, type: String,
value: null, value: null,
}, },
/** @type {?} */
_serverConfig: Object, _serverConfig: Object,
/** @type {?string} */
_docsBaseUrl: String, _docsBaseUrl: String,
_emailsChanged: Boolean,
/** /**
* For testing purposes. * For testing purposes.

View File

@@ -24,6 +24,7 @@
notify: true, notify: true,
}, },
_keys: Array, _keys: Array,
/** @type {?} */
_keyToView: Object, _keyToView: Object,
_newKey: { _newKey: {
type: String, type: String,

View File

@@ -18,6 +18,9 @@
is: 'gr-account-label', is: 'gr-account-label',
properties: { properties: {
/**
* @type {{ name: string, status: string }}
*/
account: Object, account: Object,
avatarImageSize: { avatarImageSize: {
type: Number, type: Number,

View File

@@ -102,13 +102,13 @@
} }
}, },
cursorDown(e) { cursorDown() {
if (!this.hidden) { if (!this.hidden) {
this.$.cursor.next(); this.$.cursor.next();
} }
}, },
cursorUp(e) { cursorUp() {
if (!this.hidden) { if (!this.hidden) {
this.$.cursor.previous(); this.$.cursor.previous();
} }

View File

@@ -48,7 +48,7 @@
* suggestion entry. The "value" property will be emitted if that * suggestion entry. The "value" property will be emitted if that
* suggestion is selected. * suggestion is selected.
* *
* @type {function(String): Promise<Array<Object>>} * @type {function(string): Promise<?>}
*/ */
query: { query: {
type: Function, type: Function,
@@ -95,7 +95,7 @@
value: false, value: false,
}, },
value: Object, value: String,
/** /**
* Multi mode appends autocompleted entries to the value. * Multi mode appends autocompleted entries to the value.
@@ -115,6 +115,7 @@
value: false, value: false,
}, },
/** @type {?} */
_suggestions: { _suggestions: {
type: Array, type: Array,
value() { return []; }, value() { return []; },
@@ -170,7 +171,7 @@
/** /**
* Set the text of the input without triggering the suggestion dropdown. * Set the text of the input without triggering the suggestion dropdown.
* @param {String} text The new text for the input. * @param {string} text The new text for the input.
*/ */
setText(text) { setText(text) {
this._disableSuggestions = true; this._disableSuggestions = true;
@@ -270,6 +271,9 @@
} }
}, },
/**
* @param {boolean=} opt_tabComplete
*/
_handleInputCommit(opt_tabComplete) { _handleInputCommit(opt_tabComplete) {
this._selected = this.$.suggestions.getCursorTarget(); this._selected = this.$.suggestions.getCursorTarget();
this._commit(opt_tabComplete); this._commit(opt_tabComplete);
@@ -308,11 +312,11 @@
/** /**
* Commits the suggestion, optionally firing the commit event. * Commits the suggestion, optionally firing the commit event.
* *
* @param {Boolean} silent Allows for silent committing of an autocomplete * @param {boolean=} opt_silent Allows for silent committing of an
* suggestion in order to handle cases like tab-to-complete without * autocomplete suggestion in order to handle cases like tab-to-complete
* firing the commit event. * without firing the commit event.
*/ */
_commit(silent) { _commit(opt_silent) {
// Allow values that are not in suggestion list iff suggestions are empty. // Allow values that are not in suggestion list iff suggestions are empty.
if (this._suggestions.length > 0) { if (this._suggestions.length > 0) {
this._updateValue(this._selected, this._suggestions); this._updateValue(this._selected, this._suggestions);
@@ -334,7 +338,7 @@
} }
this._suggestions = []; this._suggestions = [];
if (!silent) { if (!opt_silent) {
this.fire('commit', {value}); this.fire('commit', {value});
} }
}, },

View File

@@ -18,6 +18,7 @@
is: 'gr-change-star', is: 'gr-change-star',
properties: { properties: {
/** @type {?} */
change: { change: {
type: Object, type: Object,
notify: true, notify: true,

View File

@@ -30,6 +30,9 @@
}, },
observer: '_updateIndex', observer: '_updateIndex',
}, },
/**
* @type (?Object)
*/
target: { target: {
type: Object, type: Object,
notify: true, notify: true,
@@ -37,6 +40,7 @@
}, },
/** /**
* The height of content intended to be included with the target. * The height of content intended to be included with the target.
* @type (?number)
*/ */
_targetHeight: Number, _targetHeight: Number,
@@ -61,6 +65,8 @@
* The scroll behavior for the cursor. Values are 'never' and * The scroll behavior for the cursor. Values are 'never' and
* 'keep-visible'. 'keep-visible' will only scroll if the cursor is beyond * 'keep-visible'. 'keep-visible' will only scroll if the cursor is beyond
* the viewport. * the viewport.
* TODO (beckysiegel) figure out why it can be undefined
* @type (string|undefined)
*/ */
scrollBehavior: { scrollBehavior: {
type: String, type: String,
@@ -90,8 +96,8 @@
/** /**
* Set the cursor to an arbitrary element. * Set the cursor to an arbitrary element.
* @param {DOMElement} element * @param {!HTMLElement} element
* @param {boolean} opt_noScroll prevent any potential scrolling in response * @param {boolean=} opt_noScroll prevent any potential scrolling in response
* setting the cursor. * setting the cursor.
*/ */
setCursor(element, opt_noScroll) { setCursor(element, opt_noScroll) {
@@ -137,11 +143,11 @@
/** /**
* Move the cursor forward or backward by delta. Noop if moving past either * Move the cursor forward or backward by delta. Noop if moving past either
* end of the stop list. * end of the stop list.
* @param {Number} delta either -1 or 1. * @param {number} delta either -1 or 1.
* @param {Function} opt_condition Optional stop condition. If a condition * @param {!Function=} opt_condition Optional stop condition. If a condition
* is passed the cursor will continue to move in the specified direction * is passed the cursor will continue to move in the specified direction
* until the condition is met. * until the condition is met.
* @param {Function} opt_getTargetHeight Optional function to calculate the * @param {!Function=} opt_getTargetHeight Optional function to calculate the
* height of the target's 'section'. The height of the target itself is * height of the target's 'section'. The height of the target itself is
* sometimes different, used by the diff cursor. * sometimes different, used by the diff cursor.
* @private * @private
@@ -191,9 +197,9 @@
/** /**
* Get the next stop index indicated by the delta direction. * Get the next stop index indicated by the delta direction.
* @param {Number} delta either -1 or 1. * @param {number} delta either -1 or 1.
* @param {Function} opt_condition Optional stop condition. * @param {!Function=} opt_condition Optional stop condition.
* @return {Number} the new index. * @return {number} the new index.
* @private * @private
*/ */
_getNextindex(delta, opt_condition) { _getNextindex(delta, opt_condition) {
@@ -239,7 +245,7 @@
/** /**
* Calculate where the element is relative to the window. * Calculate where the element is relative to the window.
* @param {object} target Target to scroll to. * @param {!Object} target Target to scroll to.
* @return {number} Distance to top of the target. * @return {number} Distance to top of the target.
*/ */
_getTop(target) { _getTop(target) {

View File

@@ -23,6 +23,7 @@
value: false, value: false,
observer: '_loggedInChanged', observer: '_loggedInChanged',
}, },
schemes: Array,
selectedScheme: { selectedScheme: {
type: String, type: String,
notify: true, notify: true,

View File

@@ -96,6 +96,11 @@
this._inputText = this.value; this._inputText = this.value;
}, },
/**
* @suppress {checkTypes}
* Closure doesn't think 'e' is an Event.
* TODO(beckysiegel) figure out why.
*/
_handleEnter(e) { _handleEnter(e) {
e = this.getKeyboardEvent(e); e = this.getKeyboardEvent(e);
const target = Polymer.dom(e).rootTarget; const target = Polymer.dom(e).rootTarget;
@@ -105,6 +110,11 @@
} }
}, },
/**
* @suppress {checkTypes}
* Closure doesn't think 'e' is an Event.
* TODO(beckysiegel) figure out why.
*/
_handleEsc(e) { _handleEsc(e) {
e = this.getKeyboardEvent(e); e = this.getKeyboardEvent(e);
const target = Polymer.dom(e).rootTarget; const target = Polymer.dom(e).rootTarget;

View File

@@ -171,7 +171,9 @@
if (inParagraph) { if (inParagraph) {
// Add the finished paragraph block to the result. // Add the finished paragraph block to the result.
inParagraph = false; inParagraph = false;
out.push(block); if (block !== null) {
out.push(block);
}
} }
inList = true; inList = true;
block = {type: 'list', items: []}; block = {type: 'list', items: []};
@@ -193,7 +195,7 @@
} }
block.items.push(line); block.items.push(line);
} }
if (block != null) { if (block !== null) {
out.push(block); out.push(block);
} }
}, },
@@ -223,12 +225,16 @@
p.startsWith('- ') || p.startsWith('* '); p.startsWith('- ') || p.startsWith('* ');
}, },
_makeLinkedText(content, isPre) { /**
* @param {string} content
* @param {boolean=} opt_isPre
*/
_makeLinkedText(content, opt_isPre) {
const text = document.createElement('gr-linked-text'); const text = document.createElement('gr-linked-text');
text.config = this.config; text.config = this.config;
text.content = content; text.content = content;
text.pre = true; text.pre = true;
if (isPre) { if (opt_isPre) {
text.classList.add('pre'); text.classList.add('pre');
} }
return text; return text;

View File

@@ -1698,7 +1698,7 @@
/** /**
* Alias for _changeBaseURL.then(send). * Alias for _changeBaseURL.then(send).
* @TODO(beckysiegel) clean up comments * @todo(beckysiegel) clean up comments
* @param {string|number} changeNum * @param {string|number} changeNum
* @param {string} method * @param {string} method
* @param {?string|number} patchNum gets passed as null. * @param {?string|number} patchNum gets passed as null.
@@ -1720,7 +1720,7 @@
/** /**
* Alias for _changeBaseURL.then(fetchJSON). * Alias for _changeBaseURL.then(fetchJSON).
* @TODO(beckysiegel) clean up comments * @todo(beckysiegel) clean up comments
* @param {string|number} changeNum * @param {string|number} changeNum
* @param {string} endpoint * @param {string} endpoint
* @param {?string|number=} opt_patchNum gets passed as null. * @param {?string|number=} opt_patchNum gets passed as null.

View File

@@ -25,6 +25,7 @@
properties: { properties: {
_lastCleanup: Number, _lastCleanup: Number,
/** @type {?Storage} */
_storage: { _storage: {
type: Object, type: Object,
value() { value() {

View File

@@ -82,6 +82,7 @@
type: Boolean, type: Boolean,
value: false, value: false,
}, },
/** @type(?number) */
_colonIndex: Number, _colonIndex: Number,
_currentSearchString: { _currentSearchString: {
type: String, type: String,
@@ -193,7 +194,7 @@
}, },
_getText(value) { _getText(value) {
return this.text.substr(0, this._colonIndex) + return this.text.substr(0, this._colonIndex || 0) +
value + this.text.substr(this.$.textarea.selectionStart) + ' '; value + this.text.substr(this.$.textarea.selectionStart) + ' ';
}, },
@@ -272,7 +273,7 @@
this._currentSearchString.length + this._colonIndex + 1 || this._currentSearchString.length + this._colonIndex + 1 ||
this._currentSearchString === ' ' || this._currentSearchString === ' ' ||
this._currentSearchString === '\n' || this._currentSearchString === '\n' ||
!e.detail.value[this._colonIndex] === ':' || !(e.detail.value[this._colonIndex] === ':') ||
!this._suggestions.length) { !this._suggestions.length) {
this._resetEmojiDropdown(); this._resetEmojiDropdown();
// Otherwise open the dropdown and set the position to be just below the // Otherwise open the dropdown and set the position to be just below the

View File

@@ -47,7 +47,7 @@
* Example * Example
* // returns 'text.html' * // returns 'text.html'
* util.truncatePath.('text.html'); * util.truncatePath.('text.html');
* @return {String} Returns the truncated value of a URL. * @return {string} Returns the truncated value of a URL.
*/ */
util.truncatePath = function(path) { util.truncatePath = function(path) {
const pathPieces = path.split('/'); const pathPieces = path.split('/');