fix rename: Fixed Renaming Directories not working properly

feat dialogs.error: Added Error dialogs to show errors
This commit is contained in:
Mahdi Dibaiee 2015-09-04 02:56:33 +04:30
parent 4967c03eed
commit ffb7c68510
14 changed files with 1396 additions and 299 deletions

View File

@ -10,7 +10,8 @@ Please read the Features section below and issues to make sure your issue is not
- [x] Breadcrumb - [x] Breadcrumb
- [x] Delete Files - [x] Delete Files
- [x] Refresh - [x] Refresh
- [ ] Rename Files - [x] Rename Files
- [x] Error dialogs
- [ ] Create new files and directories - [ ] Create new files and directories
- [ ] Different views (List, Icons, etc) - [ ] Different views (List, Icons, etc)
- [ ] Share Files - [ ] Share Files

File diff suppressed because it is too large Load Diff

View File

@ -44,6 +44,7 @@
"grunt-fxos": "^0.1.2", "grunt-fxos": "^0.1.2",
"grunt-task-loader": "^0.6.0", "grunt-task-loader": "^0.6.0",
"less-plugin-clean-css": "^1.5.1", "less-plugin-clean-css": "^1.5.1",
"lodash": "^3.10.1",
"react": "^0.13.3", "react": "^0.13.3",
"react-redux": "^1.0.1", "react-redux": "^1.0.1",
"redux": "^1.0.1", "redux": "^1.0.1",

View File

@ -1,32 +1,33 @@
import { DIALOG } from 'actions/types'; import { DIALOG } from 'actions/types';
export function show(id) { export function show(id, props = {}) {
return { return {
type: DIALOG, type: DIALOG,
active: true, active: true,
id id, ...props
} }
} }
export function hide(id) { export function hide(id, props = {}) {
return { return {
type: DIALOG, type: DIALOG,
active: false, active: false,
id id, ...props
} }
} }
export function toggle(id) { export function toggle(id, props = {}) {
return { return {
type: DIALOG, type: DIALOG,
active: 'toggle', active: 'toggle',
id id, ...props
} }
} }
export function hideAll() { export function hideAll(props = {}) {
return { return {
type: DIALOG, type: DIALOG,
active: false active: false,
...props
} }
} }

View File

@ -1,32 +1,33 @@
import { MENU } from 'actions/types'; import { MENU } from 'actions/types';
export function show(id, x, y) { export function show(id, props = {}) {
return { return {
type: MENU, type: MENU,
active: true, active: true,
id, x, y id, ...props
} }
} }
export function hide(id) { export function hide(id, props = {}) {
return { return {
type: MENU, type: MENU,
active: false, active: false,
id id, ...props
} }
} }
export function toggle(id, x, y) { export function toggle(id, props = {}) {
return { return {
type: MENU, type: MENU,
active: 'toggle', active: 'toggle',
id, x, y id, ...props
} }
} }
export function hideAll() { export function hideAll(props = {}) {
return { return {
type: MENU, type: MENU,
active: false active: false,
...props
} }
} }

View File

@ -5,6 +5,7 @@ export function sdcard() {
if (SD_CACHE) return SD_CACHE; if (SD_CACHE) return SD_CACHE;
SD_CACHE = navigator.getDeviceStorage('sdcard'); SD_CACHE = navigator.getDeviceStorage('sdcard');
window.sdcard = SD_CACHE;
return SD_CACHE; return SD_CACHE;
} }
@ -13,13 +14,14 @@ export async function root() {
if (ROOT_CACHE) return ROOT_CACHE; if (ROOT_CACHE) return ROOT_CACHE;
ROOT_CACHE = await sdcard().getRoot(); ROOT_CACHE = await sdcard().getRoot();
window.root = ROOT_CACHE;
return ROOT_CACHE; return ROOT_CACHE;
} }
export async function getFile(dir = '/') { export async function getFile(dir = '/') {
let parent = await root(); let parent = await root();
if (dir === '/' || !dir) return root(); if (dir === '/' || !dir) return parent;
return await parent.get(dir); return await parent.get(dir);
} }
@ -53,33 +55,42 @@ export async function createFile(...args) {
export async function createDirectory(...args) { export async function createDirectory(...args) {
let parent = await root(); let parent = await root();
return await parent.createDirectory(...args); return parent.createDirectory(...args);
} }
export async function rename(file, newName) { export async function move(file, newPath) {
let path = (file.path || '').slice(1); // remove starting slash let path = (file.path || '').replace(/^\//, ''); // remove starting slash
let oldPath = (path + file.name); let oldPath = path + file.name;
let newPath = path + newName;
newPath = newPath.replace(/^\//, '');
let target = await getFile(oldPath); let target = await getFile(oldPath);
let parent = await root();
if (type(target) === 'Directory') { if (type(target) === 'Directory') {
await createDirectory(newPath); await parent.createDirectory(newPath);
let childs = await target.getFilesAndDirectories(); let childs = await target.getFilesAndDirectories();
for (let child of childs) { for (let child of childs) {
await rename(child, newPath + '/' + child.name); if (type(child) === 'File') {
child.path = oldPath + '/';
} }
target.delete(); await move(child, newPath + '/' + child.name);
}
await parent.remove(oldPath);
return; return;
} else { } else {
let content = await readFile(fullpath); let content = await readFile(oldPath);
let blob = new Blob([content], {type: target.type}); let blob = new Blob([content], {type: target.type});
sdcard().delete(fullpath); return new Promise((resolve, reject) => {
let request = sdcard().addNamed(blob, newPath);
sdcard().addNamed(blob, path + newName); request.onsuccess = resolve;
request.onerror = reject;
request.onabort = reject;
}).then(() => sdcard().delete(oldPath));
} }
} }

View File

@ -33,7 +33,7 @@ export default class Directory extends Component {
let left = x + width / 2 - MENU_WIDTH / 2, let left = x + width / 2 - MENU_WIDTH / 2,
top = y + height / 2 + MENU_TOP_SPACE; top = y + height / 2 + MENU_TOP_SPACE;
store.dispatch(show('directoryMenu', left, top)); store.dispatch(show('directoryMenu', {style: {left, top}}));
store.dispatch(active(this.props.index)); store.dispatch(active(this.props.index));
} }
} }

View File

@ -29,7 +29,7 @@ export default class File extends Component {
let left = x + width / 2 - MENU_WIDTH / 2, let left = x + width / 2 - MENU_WIDTH / 2,
top = y + height / 2 + MENU_TOP_SPACE; top = y + height / 2 + MENU_TOP_SPACE;
store.dispatch(show('fileMenu', left, top)); store.dispatch(show('fileMenu', {style: {left, top}}));
store.dispatch(active(this.props.index)); store.dispatch(active(this.props.index));
} }
} }

View File

@ -20,6 +20,7 @@ let DirectoryMenu = connect(state => state.get('directoryMenu'))(Menu);
let RenameDialog = connect(state => state.get('renameDialog'))(Dialog); let RenameDialog = connect(state => state.get('renameDialog'))(Dialog);
let DeleteDialog = connect(state => state.get('deleteDialog'))(Dialog); let DeleteDialog = connect(state => state.get('deleteDialog'))(Dialog);
let ErrorDialog = connect(state => state.get('errorDialog'))(Dialog);
export default class Root extends Component { export default class Root extends Component {
render() { render() {
@ -36,6 +37,7 @@ export default class Root extends Component {
<RenameDialog /> <RenameDialog />
<DeleteDialog /> <DeleteDialog />
<ErrorDialog />
</div> </div>
); );
} }

View File

@ -44,5 +44,12 @@ export default {
className: 'success' className: 'success'
} }
] ]
},
errorDialog: {
title: 'Error',
buttons: [{
text: 'Continue',
action: bind(hideAll())
}]
} }
} }

View File

@ -18,6 +18,7 @@ export default function(state = new Immutable.Map(), action) {
fileMenu: menu(state, action, 'fileMenu'), fileMenu: menu(state, action, 'fileMenu'),
directoryMenu: menu(state, action, 'directoryMenu'), directoryMenu: menu(state, action, 'directoryMenu'),
renameDialog: dialog(state, action, 'renameDialog'), renameDialog: dialog(state, action, 'renameDialog'),
deleteDialog: dialog(state, action, 'deleteDialog') deleteDialog: dialog(state, action, 'deleteDialog'),
errorDialog: dialog(state, action, 'errorDialog')
}); });
} }

View File

@ -1,11 +1,13 @@
import { DIALOG } from 'actions/types'; import { DIALOG } from 'actions/types';
import Immutable from 'immutable'; import Immutable from 'immutable';
import omit from 'lodash/object/omit';
export default function(state = new Immutable.Map({}), action, id) { export default function(state = new Immutable.Map({}), action, id) {
if (action.type === DIALOG) { if (action.type === DIALOG) {
let useful = omit(action, ['id', 'type'])
// action applied to all dialogs // action applied to all dialogs
if (!action.id) { if (!action.id) {
return Object.assign({}, state.get(id), {active: action.active}); return Object.assign({}, state.get(id), useful);
} }
if (action.id !== id) return state.get(id); if (action.id !== id) return state.get(id);
@ -13,9 +15,7 @@ export default function(state = new Immutable.Map({}), action, id) {
let target = state.get(action.id); let target = state.get(action.id);
let active = action.active === 'toggle' ? !target.get('active') : action.active; let active = action.active === 'toggle' ? !target.get('active') : action.active;
let style = Object.assign({}, state.style, {left: action.x, top: action.y}); return Object.assign({}, target, useful);
return Object.assign({}, target, { style, active });
} else { } else {
return state.get(id); return state.get(id);
} }

View File

@ -1,6 +1,8 @@
import { LIST_FILES, RENAME_FILE, DELETE_FILE } from 'actions/types'; import { LIST_FILES, RENAME_FILE, DELETE_FILE } from 'actions/types';
import { refresh } from 'actions/files-view'; import { refresh } from 'actions/files-view';
import { rename, sdcard } from 'api/files'; import { move, sdcard } from 'api/files';
import { show } from 'actions/dialog';
import store from 'store';
export default function(state = [], action) { export default function(state = [], action) {
if (action.type === LIST_FILES) { if (action.type === LIST_FILES) {
@ -11,7 +13,10 @@ export default function(state = [], action) {
if (action.type === RENAME_FILE) { if (action.type === RENAME_FILE) {
let file = state[action.file]; let file = state[action.file];
rename(file, action.name).then(refresh); move(file, (file.path || '') + action.name).then(refresh, err => {
let action = show('errorDialog', {description: err.message});
store.dispatch(action);
});
return state; return state;
} }

View File

@ -1,11 +1,13 @@
import { MENU } from 'actions/types'; import { MENU } from 'actions/types';
import Immutable from 'immutable'; import Immutable from 'immutable';
import omit from 'lodash/object/omit';
export default function(state = new Immutable.Map({}), action, id) { export default function(state = new Immutable.Map({}), action, id) {
if (action.type === MENU) { if (action.type === MENU) {
let useful = omit(action, ['id', 'type'])
// action applied to all menus // action applied to all menus
if (!action.id) { if (!action.id) {
return Object.assign({}, state.get(id), {active: action.active}); return Object.assign({}, state.get(id), useful);
} }
if (action.id !== id) return state.get(id); if (action.id !== id) return state.get(id);
@ -13,9 +15,7 @@ export default function(state = new Immutable.Map({}), action, id) {
let target = state.get(action.id); let target = state.get(action.id);
let active = action.active === 'toggle' ? !target.get('active') : action.active; let active = action.active === 'toggle' ? !target.get('active') : action.active;
let style = Object.assign({}, state.style, {left: action.x, top: action.y}); return Object.assign({}, target, useful);
return Object.assign({}, target, { style, active });
} else { } else {
return state.get(id); return state.get(id);
} }