1
0
mirror of https://github.com/chinchang/web-maker.git synced 2025-07-17 20:11:12 +02:00

add rename file support and validate duplicate file names

This commit is contained in:
Kushagra Gour
2018-10-08 16:28:17 +05:30
parent 556e507a83
commit 770f25a6ee
4 changed files with 129 additions and 31 deletions

View File

@@ -555,6 +555,7 @@ export default class ContentWrapFiles extends Component {
onFileSelect={this.fileSelectHandler.bind(this)}
onAddFile={this.props.onAddFile}
onRemoveFile={this.props.onRemoveFile}
onRenameFile={this.props.onRenameFile}
/>
</div>
<div class="code-side" id="js-code-side">

View File

@@ -52,15 +52,37 @@ export class SidePane extends Component {
this.newFileNameInput.focus();
}, 1);
}
/**
* Checks if the passed filename already exists and if so, warns the user.
* Also it passes false if the validation fails.
* @param {string} newFileName New file name to validate
*/
warnForExistingFileName(newFileName) {
// We also check for fileBeingRenamed !== file because when a file being renamed is
// asked to be set same name, then that should not match and warn here.
if (
this.props.files.some(
file =>
file.name === newFileName && this.state.fileBeingRenamed !== file
)
) {
alert(`A file with name ${newFileName} already exists.`);
return false;
}
return true;
}
addFile() {
// This gets called twice when enter is pressed, because blur also fires.
if (!this.newFileNameInput) {
return;
}
const fileName = this.newFileNameInput.value;
if (fileName) {
this.props.onAddFile(fileName);
const newFileName = this.newFileNameInput.value;
if (!this.warnForExistingFileName(newFileName)) {
return;
}
if (newFileName) {
this.props.onAddFile(newFileName);
}
this.setState({ isEditing: false });
}
@@ -78,6 +100,36 @@ export class SidePane extends Component {
this.props.onRemoveFile(file);
}
}
renameFile() {
// This gets called twice when enter is pressed, because blur also fires.
if (!this.renameFileNameInput) {
return;
}
const newFileName = this.renameFileNameInput.value;
if (!this.warnForExistingFileName(newFileName)) {
return;
}
if (newFileName) {
this.props.onRenameFile(this.state.fileBeingRenamed.name, newFileName);
}
this.setState({ fileBeingRenamed: null });
}
renameFileNameInputKeyDownHandler(e) {
if (e.which === ENTER_KEY) {
this.renameFile();
} else if (e.which === ESCAPE_KEY) {
this.setState({ fileBeingRenamed: null });
}
}
renameFileClickHandler(file, e) {
e.stopPropagation();
this.setState({
fileBeingRenamed: file
});
setTimeout(() => {
this.renameFileNameInput.focus();
}, 1);
}
render() {
const { files, onFileSelect, selectedFile, onRemoveFile } = this.props;
@@ -112,32 +164,57 @@ export class SidePane extends Component {
) : null}
{files.map(file => (
<div>
<button
class={`sidebar__file ${
selectedFile === file ? 'selected' : ''
}`}
type="button"
onClick={onFileSelect.bind(null, file)}
>
<div class="flex flex-v-center">
<FileIcon fileName={file.name} />
{file.name}
</div>
<div class="sidebar__file-options">
<button
type="button"
class="btn btn--dark"
onClick={this.removeFileClickHandler.bind(this, file)}
>
<svg
viewBox="0 0 24 24"
style="vertical-align:middle;width:14px;height:14px"
{file === this.state.fileBeingRenamed ? (
<input
type="text"
ref={el => (this.renameFileNameInput = el)}
value={file.name}
onBlur={this.renameFile.bind(this)}
onKeyUpCapture={this.renameFileNameInputKeyDownHandler.bind(
this
)}
/>
) : (
<button
class={`sidebar__file ${
selectedFile === file ? 'selected' : ''
}`}
type="button"
onClick={onFileSelect.bind(null, file)}
>
<div class="flex flex-v-center">
<FileIcon fileName={file.name} />
{file.name}
</div>
<div class="sidebar__file-options">
<button
type="button"
class="btn btn--dark"
onClick={this.renameFileClickHandler.bind(this, file)}
>
<path d="M19,4H15.5L14.5,3H9.5L8.5,4H5V6H19M6,19A2,2 0 0,0 8,21H16A2,2 0 0,0 18,19V7H6V19Z" />
</svg>
</button>
</div>
</button>
<svg
viewBox="0 0 24 24"
style="vertical-align:middle;width:14px;height:14px"
>
<path d="M20.71,7.04C21.1,6.65 21.1,6 20.71,5.63L18.37,3.29C18,2.9 17.35,2.9 16.96,3.29L15.12,5.12L18.87,8.87M3,17.25V21H6.75L17.81,9.93L14.06,6.18L3,17.25Z" />
</svg>
</button>
<button
type="button"
class="btn btn--dark"
onClick={this.removeFileClickHandler.bind(this, file)}
>
<svg
viewBox="0 0 24 24"
style="vertical-align:middle;width:14px;height:14px"
>
<path d="M19,4H15.5L14.5,3H9.5L8.5,4H5V6H19M6,19A2,2 0 0,0 8,21H16A2,2 0 0,0 18,19V7H6V19Z" />
</svg>
</button>
</div>
</button>
)}
</div>
))}
</div>

View File

@@ -490,7 +490,9 @@ export default class App extends Component {
isKeyboardShortcutsModalOpen: !this.state.isKeyboardShortcutsModalOpen
});
trackEvent('ui', 'showKeyboardShortcutsShortcut');
} else if (event.keyCode === 27) {
} else if (event.keyCode === 27 && event.target.tagName !== 'INPUT') {
// We might be listening on keydown for some input inside the app. In that case
// we don't want this to trigger which in turn focuses back the last editor.
this.closeSavedItemsPane();
}
});
@@ -1202,6 +1204,19 @@ export default class App extends Component {
}
});
}
renameFileHandler(oldFileName, newFileName) {
this.setState({
currentItem: {
...this.state.currentItem,
files: this.state.currentItem.files.map(file => {
if (file.name === oldFileName) {
return { ...file, name: newFileName };
}
return file;
})
}
});
}
render() {
return (
@@ -1236,6 +1251,7 @@ export default class App extends Component {
onSplitUpdate={this.splitUpdateHandler.bind(this)}
onAddFile={this.addFileHandler.bind(this)}
onRemoveFile={this.removeFileHandler.bind(this)}
onRenameFile={this.renameFileHandler.bind(this)}
/>
) : (
<ContentWrap

View File

@@ -1621,9 +1621,10 @@ body:not(.is-app) .show-when-app {
width: 100%;
text-align: left;
display: flex;
padding: 2px 4px;
padding: 5px 4px;
align-items: center;
justify-content: space-between;
position: relative;
}
.sidebar__file.selected {
color: white;
@@ -1636,10 +1637,13 @@ body:not(.is-app) .show-when-app {
margin-right: 10px;
}
.sidebar__file-options {
position: absolute;
right: 0;
visibility: hidden;
}
.sidebar__file:hover .sidebar__file-options,
.sidebar__file:focus .sidebar__file-options {
.sidebar__file:focus .sidebar__file-options,
.sidebar__file:focus-within .sidebar__file-options {
visibility: visible;
}