feat(archive): ability to archive / extract files in zip format
fix(selectview): clear active files when user taps on select-view button in toolbar resolve #10 resolve #12
This commit is contained in:
parent
44340abb61
commit
dfb7d8aa72
11677
build/main.js
11677
build/main.js
File diff suppressed because it is too large
Load Diff
@ -25,7 +25,9 @@
|
||||
"node": ">=0.12.0"
|
||||
},
|
||||
"homepage": "https://github.com/mdibaiee/",
|
||||
"dependencies": {},
|
||||
"dependencies": {
|
||||
"jszip": "2.5.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel": "^5.8.23",
|
||||
"babelify": "^6.2.0",
|
||||
|
15
src/js/actions/compress.js
Normal file
15
src/js/actions/compress.js
Normal file
@ -0,0 +1,15 @@
|
||||
import { COMPRESS, DECOMPRESS } from './types';
|
||||
|
||||
export function compress(file) {
|
||||
return {
|
||||
type: COMPRESS,
|
||||
file
|
||||
}
|
||||
}
|
||||
|
||||
export function decompress(file) {
|
||||
return {
|
||||
type: DECOMPRESS,
|
||||
file
|
||||
}
|
||||
}
|
@ -9,6 +9,9 @@ const TYPES = {
|
||||
REFRESH: Symbol('REFRESH'),
|
||||
SORT: Symbol('SORT'),
|
||||
|
||||
COMPRESS: Symbol('COMPRESS'),
|
||||
DECOMPRESS: Symbol('DECOMPRESS'),
|
||||
|
||||
NEW_FILE: Symbol('NEW_FILE'),
|
||||
CREATE_FILE: Symbol('CREATE_FILE'),
|
||||
SHARE_FILE: Symbol('SHARE_FILE'),
|
||||
|
@ -70,6 +70,12 @@ export async function children(dir, gatherInfo) {
|
||||
return childs;
|
||||
}
|
||||
|
||||
export async function isDirectory(path) {
|
||||
let file = await getFile(path);
|
||||
|
||||
return !(file instanceof Blob);
|
||||
}
|
||||
|
||||
export async function readFile(path) {
|
||||
let file = await getFile(path);
|
||||
|
||||
@ -85,6 +91,16 @@ export async function readFile(path) {
|
||||
});
|
||||
}
|
||||
|
||||
export async function writeFile(path, content) {
|
||||
let request = sdcard().addNamed(content, path);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
request.onsuccess = resolve;
|
||||
request.onerror = reject;
|
||||
request.onabort = reject;
|
||||
});
|
||||
}
|
||||
|
||||
export async function createFile(...args) {
|
||||
let parent = await root();
|
||||
|
||||
@ -147,11 +163,6 @@ export async function copy(file, newPath) {
|
||||
|
||||
let blob = new Blob([content], {type: target.type});
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
let request = sdcard().addNamed(blob, newPath);
|
||||
request.onsuccess = resolve;
|
||||
request.onerror = reject;
|
||||
request.onabort = reject;
|
||||
});
|
||||
return writeFile(newPath, blob);
|
||||
}
|
||||
}
|
||||
|
@ -37,7 +37,6 @@ export default class Breadcrumb extends Component {
|
||||
let path = current.join('/').replace(/^\//, ''); // remove starting slash
|
||||
let key = directories.length + index;
|
||||
let style = { zIndex: arr.length - index};
|
||||
console.log('history', dir)
|
||||
|
||||
return (
|
||||
<span key={key} className='history' onClick={bind(changedir(path))} style={style}>{dir}</span>
|
||||
|
@ -2,6 +2,7 @@ import React, { Component } from 'react';
|
||||
import { refresh, selectView } from 'actions/files-view';
|
||||
import { show as showDialog } from 'actions/dialog';
|
||||
import { show as showMenu } from 'actions/menu';
|
||||
import active from 'actions/active-file';
|
||||
import settings from 'actions/settings';
|
||||
import store, { bind } from 'store';
|
||||
import { MENU_WIDTH } from './menu';
|
||||
@ -13,7 +14,7 @@ export default class Toolbar extends Component {
|
||||
<button className='icon-back tour-item' onClick={this.goUp} />
|
||||
<button className='icon-plus tour-item' onClick={this.newFile} />
|
||||
<button className='icon-refresh tour-item' onClick={bind(refresh())} />
|
||||
<button className='icon-select tour-item' onClick={bind(selectView('toggle'))} />
|
||||
<button className='icon-select tour-item' onClick={this.selectView} />
|
||||
<button className='icon-more tour-item' onClick={this.showMore.bind(this)} ref='more' />
|
||||
</div>
|
||||
);
|
||||
@ -39,6 +40,11 @@ export default class Toolbar extends Component {
|
||||
store.dispatch(changedir(up));
|
||||
}
|
||||
|
||||
selectView() {
|
||||
store.dispatch(selectView('toggle'));
|
||||
store.dispatch(active());
|
||||
}
|
||||
|
||||
newFile() {
|
||||
let cwd = store.getState().get('cwd');
|
||||
let action = showDialog('createDialog', {
|
||||
|
@ -2,6 +2,7 @@ import { hideAll } from 'actions/menu';
|
||||
import { show } from 'actions/dialog';
|
||||
import { selectView } from 'actions/files-view';
|
||||
import { copy, move } from 'actions/file';
|
||||
import { compress, decompress } from 'actions/compress';
|
||||
import store from 'store';
|
||||
|
||||
const entryMenu = {
|
||||
@ -64,6 +65,28 @@ const entryMenu = {
|
||||
blob
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'Extract',
|
||||
enabled() {
|
||||
let active = store.getState().get('activeFile');
|
||||
|
||||
if (active) console.log(active[0].name);
|
||||
return active && active[0].name.indexOf('.zip') > -1;
|
||||
},
|
||||
action() {
|
||||
let active = store.getState().get('activeFile');
|
||||
|
||||
store.dispatch(decompress(active));
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'Archive',
|
||||
action() {
|
||||
let active = store.getState().get('activeFile');
|
||||
|
||||
store.dispatch(compress(active));
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
@ -142,6 +165,14 @@ const moreMenu = {
|
||||
})
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'Archive',
|
||||
action() {
|
||||
let active = store.getState().get('activeFile');
|
||||
|
||||
store.dispatch(compress(active));
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -1,13 +1,9 @@
|
||||
import { ACTIVE_FILE, CHANGE_DIRECTORY } from 'actions/types';
|
||||
import { ACTIVE_FILE, SELECT_VIEW } from 'actions/types';
|
||||
|
||||
export default function(state = null, action) {
|
||||
if (action.type === ACTIVE_FILE) {
|
||||
return action.file;
|
||||
}
|
||||
|
||||
if (action.type === CHANGE_DIRECTORY) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
@ -1,9 +1,10 @@
|
||||
import { LIST_FILES, RENAME_FILE, DELETE_FILE, CREATE_FILE, MOVE_FILE, COPY_FILE, SEARCH } from 'actions/types';
|
||||
import { LIST_FILES, RENAME_FILE, DELETE_FILE, CREATE_FILE, MOVE_FILE, COPY_FILE, SEARCH, COMPRESS, DECOMPRESS } from 'actions/types';
|
||||
import zip from 'jszip';
|
||||
import { refresh } from 'actions/files-view';
|
||||
import { move, remove, sdcard, createFile, createDirectory, copy } from 'api/files';
|
||||
import { move, remove, sdcard, createFile, readFile, writeFile, createDirectory, getFile, copy, children } from 'api/files';
|
||||
import { show } from 'actions/dialog';
|
||||
import store, { bind } from 'store';
|
||||
import { reportError, type } from 'utils';
|
||||
import { reportError, type, normalize } from 'utils';
|
||||
|
||||
let boundRefresh = bind(refresh());
|
||||
|
||||
@ -74,7 +75,7 @@ export default function(state = [], action) {
|
||||
|
||||
if (action.type === DELETE_FILE) {
|
||||
let all = Promise.all(action.file.map(file => {
|
||||
let path = ((file.path || '') + file.name).replace(/^\//, '');
|
||||
let path = normalize((file.path || '') + file.name);
|
||||
return remove(path, true);
|
||||
}))
|
||||
|
||||
@ -82,6 +83,69 @@ export default function(state = [], action) {
|
||||
return state;
|
||||
}
|
||||
|
||||
if (action.type === COMPRESS) {
|
||||
let archive = new zip();
|
||||
let cwd = store.getState().get('cwd');
|
||||
|
||||
let all = Promise.all(action.file.map(function addFile(file) {
|
||||
console.log('addFile', file);
|
||||
let path = normalize((file.path || '') + file.name);
|
||||
let archivePath = path.slice(cwd.length);
|
||||
// directory
|
||||
if (!(file instanceof Blob)) {
|
||||
let folder = archive.folder(file.name);
|
||||
|
||||
return children(path).then(files => {
|
||||
return Promise.all(files.map(child => {
|
||||
return addFile(child);
|
||||
|
||||
// return readFile(childPath).then(content => {
|
||||
// let blob = new Blob([content]);
|
||||
// folder.file(child.name, blob);
|
||||
// });
|
||||
}));
|
||||
})
|
||||
}
|
||||
|
||||
return readFile(path).then(content => {
|
||||
archive.file(archivePath + '/' + file.name, content);
|
||||
});
|
||||
}))
|
||||
|
||||
all.then(() => {
|
||||
let buffer = archive.generate({ type: 'nodebuffer' });
|
||||
console.log(buffer);
|
||||
let blob = new Blob([buffer], { type: 'application/zip' });
|
||||
|
||||
let cwd = store.getState().get('cwd');
|
||||
let path = normalize(cwd + '/archive.zip');
|
||||
return writeFile(path, blob);
|
||||
}).then(boundRefresh).catch(reportError);
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
if (action.type === DECOMPRESS) {
|
||||
let file = action.file[0];
|
||||
let path = normalize((file.path || '') + file.name);
|
||||
readFile(path).then(content => {
|
||||
let archive = new zip(content);
|
||||
let files = Object.keys(archive.files);
|
||||
|
||||
let all = Promise.all(files.map(name => {
|
||||
let buffer = archive.files[name].asArrayBuffer();
|
||||
let blob = new Blob([buffer]);
|
||||
|
||||
let cwd = store.getState().get('cwd');
|
||||
let filePath = normalize(cwd + '/' + name);
|
||||
|
||||
return writeFile(filePath, blob);
|
||||
}));
|
||||
|
||||
all.then(boundRefresh, reportError);
|
||||
});
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user