2018-05-04 18:07:28 +00:00
|
|
|
import store from '../store';
|
|
|
|
import utils from './utils';
|
|
|
|
|
|
|
|
const forbiddenFolderNameMatcher = /^\.stackedit-data$|^\.stackedit-trash$|\.md$|\.sync$|\.publish$/;
|
|
|
|
|
|
|
|
export default {
|
|
|
|
/**
|
|
|
|
* Create a file in the store with the specified fields.
|
|
|
|
*/
|
2018-05-06 00:46:33 +00:00
|
|
|
createFile({
|
|
|
|
name,
|
|
|
|
parentId,
|
|
|
|
text,
|
|
|
|
properties,
|
|
|
|
discussions,
|
|
|
|
comments,
|
|
|
|
} = {}, background = false) {
|
2018-05-04 18:07:28 +00:00
|
|
|
const id = utils.uid();
|
|
|
|
const file = {
|
|
|
|
id,
|
2018-05-06 00:46:33 +00:00
|
|
|
name: utils.sanitizeName(name),
|
|
|
|
parentId: parentId || null,
|
2018-05-04 18:07:28 +00:00
|
|
|
};
|
|
|
|
const content = {
|
|
|
|
id: `${id}/content`,
|
2018-05-06 00:46:33 +00:00
|
|
|
text: utils.sanitizeText(text || store.getters['data/computedSettings'].newFileContent),
|
|
|
|
properties: utils
|
|
|
|
.sanitizeText(properties || store.getters['data/computedSettings'].newFileProperties),
|
|
|
|
discussions: discussions || {},
|
|
|
|
comments: comments || {},
|
2018-05-04 18:07:28 +00:00
|
|
|
};
|
2018-05-06 00:46:33 +00:00
|
|
|
const nameStripped = file.name !== utils.defaultName && file.name !== name;
|
2018-05-04 18:07:28 +00:00
|
|
|
|
|
|
|
// Check if there is a path conflict
|
|
|
|
const workspaceUniquePaths = store.getters['workspace/hasUniquePaths'];
|
|
|
|
let pathConflict;
|
|
|
|
if (workspaceUniquePaths) {
|
|
|
|
const parentPath = store.getters.itemPaths[file.parentId] || '';
|
|
|
|
const path = parentPath + file.name;
|
|
|
|
pathConflict = !!store.getters.pathItems[path];
|
|
|
|
}
|
|
|
|
|
|
|
|
// Show warning dialogs and then save in the store
|
|
|
|
return Promise.resolve()
|
2018-05-06 00:46:33 +00:00
|
|
|
.then(() => !background && nameStripped && store.dispatch('modal/stripName', name))
|
|
|
|
.then(() => !background && pathConflict && store.dispatch('modal/pathConflict', name))
|
2018-05-04 18:07:28 +00:00
|
|
|
.then(() => {
|
|
|
|
store.commit('content/setItem', content);
|
|
|
|
store.commit('file/setItem', file);
|
|
|
|
if (workspaceUniquePaths) {
|
|
|
|
this.makePathUnique(id);
|
|
|
|
}
|
|
|
|
return store.state.file.itemMap[id];
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Make sanity checks and then create/update the folder/file in the store.
|
|
|
|
*/
|
|
|
|
async storeItem(item, background = false) {
|
|
|
|
const id = item.id || utils.uid();
|
|
|
|
const sanitizedName = utils.sanitizeName(item.name);
|
|
|
|
|
|
|
|
if (item.type === 'folder' && forbiddenFolderNameMatcher.exec(sanitizedName)) {
|
|
|
|
if (background) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
await store.dispatch('modal/unauthorizedName', item.name);
|
|
|
|
throw new Error('Unauthorized name.');
|
|
|
|
}
|
|
|
|
|
|
|
|
const workspaceUniquePaths = store.getters['workspace/hasUniquePaths'];
|
|
|
|
|
|
|
|
// Show warning dialogs
|
|
|
|
if (!background) {
|
|
|
|
// If name has been stripped
|
|
|
|
if (sanitizedName !== utils.defaultName && sanitizedName !== item.name) {
|
|
|
|
await store.dispatch('modal/stripName', item.name);
|
|
|
|
}
|
|
|
|
// Check if there is a path conflict
|
|
|
|
if (workspaceUniquePaths) {
|
|
|
|
const parentPath = store.getters.itemPaths[item.parentId] || '';
|
|
|
|
const path = parentPath + sanitizedName;
|
|
|
|
const pathItems = store.getters.pathItems[path] || [];
|
|
|
|
if (pathItems.some(itemWithSamePath => itemWithSamePath.id !== id)) {
|
|
|
|
await store.dispatch('modal/pathConflict', item.name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Save item in the store
|
|
|
|
store.commit(`${item.type}/setItem`, {
|
|
|
|
id,
|
|
|
|
parentId: item.parentId || null,
|
|
|
|
name: sanitizedName,
|
|
|
|
});
|
|
|
|
|
|
|
|
// Ensure path uniqueness
|
|
|
|
if (workspaceUniquePaths) {
|
|
|
|
this.makePathUnique(id);
|
|
|
|
}
|
|
|
|
return store.getters.allItemMap[id];
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Delete a file in the store and all its related items.
|
|
|
|
*/
|
|
|
|
deleteFile(fileId) {
|
|
|
|
// Delete the file
|
|
|
|
store.commit('file/deleteItem', fileId);
|
|
|
|
// Delete the content
|
|
|
|
store.commit('content/deleteItem', `${fileId}/content`);
|
|
|
|
// Delete the syncedContent
|
|
|
|
store.commit('syncedContent/deleteItem', `${fileId}/syncedContent`);
|
|
|
|
// Delete the contentState
|
|
|
|
store.commit('contentState/deleteItem', `${fileId}/contentState`);
|
|
|
|
// Delete sync locations
|
|
|
|
(store.getters['syncLocation/groupedByFileId'][fileId] || [])
|
|
|
|
.forEach(item => store.commit('syncLocation/deleteItem', item.id));
|
|
|
|
// Delete publish locations
|
|
|
|
(store.getters['publishLocation/groupedByFileId'][fileId] || [])
|
|
|
|
.forEach(item => store.commit('publishLocation/deleteItem', item.id));
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Ensure two files/folders don't have the same path if the workspace doesn't support it.
|
|
|
|
*/
|
|
|
|
ensureUniquePaths() {
|
|
|
|
if (store.getters['workspace/hasUniquePaths']) {
|
|
|
|
if (Object.keys(store.getters.itemPaths).some(id => this.makePathUnique(id))) {
|
|
|
|
this.ensureUniquePaths();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return false if the file/folder path is unique.
|
|
|
|
* Add a prefix to its name and return true otherwise.
|
|
|
|
*/
|
|
|
|
makePathUnique(id) {
|
2018-05-06 00:46:33 +00:00
|
|
|
const { pathItems, allItemMap, itemPaths } = store.getters;
|
|
|
|
const item = allItemMap[id];
|
2018-05-04 18:07:28 +00:00
|
|
|
if (!item) {
|
|
|
|
return false;
|
|
|
|
}
|
2018-05-06 00:46:33 +00:00
|
|
|
let path = itemPaths[id];
|
2018-05-04 18:07:28 +00:00
|
|
|
if (pathItems[path].length === 1) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
const isFolder = item.type === 'folder';
|
|
|
|
if (isFolder) {
|
|
|
|
// Remove trailing slash
|
|
|
|
path = path.slice(0, -1);
|
|
|
|
}
|
|
|
|
for (let suffix = 1; ; suffix += 1) {
|
|
|
|
let pathWithPrefix = `${path}.${suffix}`;
|
|
|
|
if (isFolder) {
|
|
|
|
pathWithPrefix += '/';
|
|
|
|
}
|
|
|
|
if (!pathItems[pathWithPrefix]) {
|
|
|
|
store.commit(`${item.type}/patchItem`, {
|
|
|
|
id: item.id,
|
|
|
|
name: `${item.name}.${suffix}`,
|
|
|
|
});
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
};
|