
These tags are preserved by the Closure compiler and vulcanize in order to serve the license notices embedded in the outputs. In a standalone Gerrit server, these license are also covered in the LICENSES.txt served with the documentation. When serving PG assets from a CDN, it's less obvious what the corresponding LICENSES.txt file is, since the CDN is not directly linked to a running Gerrit server. Safer to embed the licenses in the assets themselves. Change-Id: Id1add1451fad1baa7916882a6bda02c326ccc988
228 lines
6.6 KiB
JavaScript
228 lines
6.6 KiB
JavaScript
/**
|
|
* @license
|
|
* Copyright (C) 2017 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
(function() {
|
|
'use strict';
|
|
|
|
Polymer({
|
|
is: 'gr-edit-controls',
|
|
properties: {
|
|
change: Object,
|
|
patchNum: String,
|
|
|
|
/**
|
|
* TODO(kaspern): by default, the RESTORE action should be hidden in the
|
|
* file-list as it is a per-file action only. Remove this default value
|
|
* when the Actions dictionary is moved to a shared constants file and
|
|
* use the hiddenActions property in the parent component.
|
|
*/
|
|
hiddenActions: {
|
|
type: Array,
|
|
value() { return [GrEditConstants.Actions.RESTORE.id]; },
|
|
},
|
|
|
|
_actions: {
|
|
type: Array,
|
|
value() { return Object.values(GrEditConstants.Actions); },
|
|
},
|
|
_path: {
|
|
type: String,
|
|
value: '',
|
|
},
|
|
_newPath: {
|
|
type: String,
|
|
value: '',
|
|
},
|
|
_query: {
|
|
type: Function,
|
|
value() {
|
|
return this._queryFiles.bind(this);
|
|
},
|
|
},
|
|
},
|
|
|
|
behaviors: [
|
|
Gerrit.PatchSetBehavior,
|
|
],
|
|
|
|
_handleTap(e) {
|
|
e.preventDefault();
|
|
const action = Polymer.dom(e).localTarget.id;
|
|
switch (action) {
|
|
case GrEditConstants.Actions.OPEN.id:
|
|
this.openOpenDialog();
|
|
return;
|
|
case GrEditConstants.Actions.DELETE.id:
|
|
this.openDeleteDialog();
|
|
return;
|
|
case GrEditConstants.Actions.RENAME.id:
|
|
this.openRenameDialog();
|
|
return;
|
|
case GrEditConstants.Actions.RESTORE.id:
|
|
this.openRestoreDialog();
|
|
return;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* @param {string=} opt_path
|
|
*/
|
|
openOpenDialog(opt_path) {
|
|
if (opt_path) { this._path = opt_path; }
|
|
return this._showDialog(this.$.openDialog);
|
|
},
|
|
|
|
/**
|
|
* @param {string=} opt_path
|
|
*/
|
|
openDeleteDialog(opt_path) {
|
|
if (opt_path) { this._path = opt_path; }
|
|
return this._showDialog(this.$.deleteDialog);
|
|
},
|
|
|
|
/**
|
|
* @param {string=} opt_path
|
|
*/
|
|
openRenameDialog(opt_path) {
|
|
if (opt_path) { this._path = opt_path; }
|
|
return this._showDialog(this.$.renameDialog);
|
|
},
|
|
|
|
/**
|
|
* @param {string=} opt_path
|
|
*/
|
|
openRestoreDialog(opt_path) {
|
|
if (opt_path) { this._path = opt_path; }
|
|
return this._showDialog(this.$.restoreDialog);
|
|
},
|
|
|
|
/**
|
|
* Given a path string, checks that it is a valid file path.
|
|
* @param {string} path
|
|
* @return {boolean}
|
|
*/
|
|
_isValidPath(path) {
|
|
// Double negation needed for strict boolean return type.
|
|
return !!path.length && !path.endsWith('/');
|
|
},
|
|
|
|
_computeRenameDisabled(path, newPath) {
|
|
return this._isValidPath(path) && this._isValidPath(newPath);
|
|
},
|
|
|
|
/**
|
|
* Given a dom event, gets the dialog that lies along this event path.
|
|
* @param {!Event} e
|
|
* @return {!Element|undefined}
|
|
*/
|
|
_getDialogFromEvent(e) {
|
|
return Polymer.dom(e).path.find(element => {
|
|
if (!element.classList) { return false; }
|
|
return element.classList.contains('dialog');
|
|
});
|
|
},
|
|
|
|
_showDialog(dialog) {
|
|
// Some dialogs may not fire their on-close event when closed in certain
|
|
// ways (e.g. by clicking outside the dialog body). This call prevents
|
|
// multiple dialogs from being shown in the same overlay.
|
|
this._hideAllDialogs();
|
|
|
|
return this.$.overlay.open().then(() => {
|
|
dialog.classList.toggle('invisible', false);
|
|
const autocomplete = dialog.querySelector('gr-autocomplete');
|
|
if (autocomplete) { autocomplete.focus(); }
|
|
this.async(() => { this.$.overlay.center(); }, 1);
|
|
});
|
|
},
|
|
|
|
_hideAllDialogs() {
|
|
const dialogs = Polymer.dom(this.root).querySelectorAll('.dialog');
|
|
for (const dialog of dialogs) { this._closeDialog(dialog); }
|
|
},
|
|
|
|
/**
|
|
* @param {Element|undefined} dialog
|
|
* @param {boolean=} clearInputs
|
|
*/
|
|
_closeDialog(dialog, clearInputs) {
|
|
if (!dialog) { return; }
|
|
|
|
if (clearInputs) {
|
|
// Dialog may have autocompletes and plain inputs -- as these have
|
|
// different properties representing their bound text, it is easier to
|
|
// just make two separate queries.
|
|
dialog.querySelectorAll('gr-autocomplete')
|
|
.forEach(input => { input.text = ''; });
|
|
dialog.querySelectorAll('input')
|
|
.forEach(input => { input.bindValue = ''; });
|
|
}
|
|
|
|
dialog.classList.toggle('invisible', true);
|
|
return this.$.overlay.close();
|
|
},
|
|
|
|
_handleDialogCancel(e) {
|
|
this._closeDialog(this._getDialogFromEvent(e));
|
|
},
|
|
|
|
_handleOpenConfirm(e) {
|
|
const url = Gerrit.Nav.getEditUrlForDiff(this.change, this._path,
|
|
this.patchNum);
|
|
Gerrit.Nav.navigateToRelativeUrl(url);
|
|
this._closeDialog(this._getDialogFromEvent(e), true);
|
|
},
|
|
|
|
_handleDeleteConfirm(e) {
|
|
this.$.restAPI.deleteFileInChangeEdit(this.change._number, this._path)
|
|
.then(res => {
|
|
if (!res.ok) { return; }
|
|
this._closeDialog(this._getDialogFromEvent(e), true);
|
|
Gerrit.Nav.navigateToChange(this.change);
|
|
});
|
|
},
|
|
|
|
_handleRestoreConfirm(e) {
|
|
this.$.restAPI.restoreFileInChangeEdit(this.change._number, this._path)
|
|
.then(res => {
|
|
if (!res.ok) { return; }
|
|
this._closeDialog(this._getDialogFromEvent(e), true);
|
|
Gerrit.Nav.navigateToChange(this.change);
|
|
});
|
|
},
|
|
|
|
_handleRenameConfirm(e) {
|
|
return this.$.restAPI.renameFileInChangeEdit(this.change._number,
|
|
this._path, this._newPath).then(res => {
|
|
if (!res.ok) { return; }
|
|
this._closeDialog(this._getDialogFromEvent(e), true);
|
|
Gerrit.Nav.navigateToChange(this.change);
|
|
});
|
|
},
|
|
|
|
_queryFiles(input) {
|
|
return this.$.restAPI.queryChangeFiles(this.change._number,
|
|
this.patchNum, input).then(res => res.map(file => {
|
|
return {name: file};
|
|
}));
|
|
},
|
|
|
|
_computeIsInvisible(id, hiddenActions) {
|
|
return hiddenActions.includes(id) ? 'invisible' : '';
|
|
},
|
|
});
|
|
})();
|