Merge pull request #11 from coderaiser/dev

v0.8.2
This commit is contained in:
coderaiser 2014-03-03 16:10:46 +02:00
commit 7f89ca1b8e
34 changed files with 1210 additions and 1054 deletions

View file

@ -1,10 +1,71 @@
2013.02.13, v0.8.1
2014.03.03, v0.8.2
fix:
- (style) .loading: spinner size
- (server) createRedirect: add sslPort
- (server) http -> procol
- (server) start: http -> HTTP
- (dom) promptDeleteSelected: pCurrentFile -> current
- (rest) onDelete: func(null, body) -> func
- (rest) onStat: add var
- (cloudcmd) change index path
- (server) start: url -> URL
- (server) start: SSLPort -> sslPort
- (server) start: Port -> port
- (dom) getCurrentDirPath: "," -> ";"
- (dom) renameCurrent: rm dir listing from Storage
- (client) loadDir: do not change dir after fail load
- (cloudcmd) route: add name
- (style) .files height: 95% -> 85%
- (dom) setCurrent: set id of li to
- (client) ajaxLoad: do not save path to history if content not load
- (path) #js-path -> .js-path: 2 pathes on a page
feature:
- (package) rm pty.js
- (view) rm spinner from doBefore, add to view
- (package) add pty.js
- (package) minify: v0.2.5 -> 0.2.6
- (client) initModules doBefore: add filepicker
- (menu) DOM.Images -> Images, "From Cloud" -> "From FilePicker"
- (index) change favicon
- (favicon) add
- (ext) .ico: vnd.microsoft.icon -> x-icon
- (index) hide .path-icon when no js
- (style) .loading top: 1px -> 2px
- (storage) get: ret -> this
- (favicon) optimize img
- (cloudcmd) optimize image
- (deleteSelected) rm param notSet
- (fs) add fs folder
- (style) height < 800px: .fm height: 74%
- (style) set bigger font for width < 600px
- (style)if height < 800px: .fm height 85%
- (css) html: change height
- (style) show only part of name is to long
- (index) add style for no js: hide keys, show one panel
- (style) .cmd-button: height: 30px
- (polyfill) rm localStorage
- (refactor) .js-left -> [data=js-left]
- (rest) add onFSPut
- (style) change .fm height to 75% on small screen heights
- (style) change name color on small screens
- (style) rm duplicate .fm-header
- (edit) add save on F2
- (storage) change to async
- (storage) add
- (dom) add storage
- (listeners) change touchend
- (key) setCurrentByLatter: add numbers
2014.02.13, v0.8.1
fix:
- (commander) changeUIDToName: doesn't work on win
2013.02.13, v0.8.0
2014.02.13, v0.8.0
fix:
- (test) template

65
HELP.md
View file

@ -1,15 +1,17 @@
Cloud Commander v0.8.1 [![NPM version][NPMIMGURL]][NPMURL] [![Dependency Status][DependencyStatusIMGURL]][DependencyStatusURL] [![Build Status][BuildStatusIMGURL]][BuildStatusURL]
Cloud Commander v0.8.2 [![NPM version][NPMIMGURL]][NPMURL] [![Dependency Status][DependencyStatusIMGURL]][DependencyStatusURL] [![Build Status][BuildStatusIMGURL]][BuildStatusURL] [![License][LicenseIMGURL]][LicenseURL] [![Flattr][FlattrIMGURL]][FlattrURL]
===============
###[Main][MainURL] [Blog][BlogURL] Live(![IO][IO_LIVE_IMG] [IO][IOURL], ![JitSu][JitSu_LIVE_IMG] [JitSu][JitSuURL], ![Heroku][Heroku_LIVE_IMG] [Heroku][HerokuURL])
[NPMIMGURL]: https://badge.fury.io/js/cloudcmd.png
[BuildStatusIMGURL]: https://secure.travis-ci.org/coderaiser/cloudcmd.png?branch=master
[NPMIMGURL]: https://img.shields.io/npm/v/cloudcmd.svg
[BuildStatusIMGURL]: https://api.travis-ci.org/coderaiser/cloudcmd.png?branch=dev
[DependencyStatusIMGURL]: https://gemnasium.com/coderaiser/cloudcmd.png
[FlattrIMGURL]: https://api.flattr.com/button/flattr-badge-large.png
[NPM_INFO_IMG]: https://nodei.co/npm/cloudcmd.png
[FlattrIMGURL]: https://img.shields.io/badge/flattr-donate-317BF9.svg
[LicenseIMGURL]: https://img.shields.io/badge/license-MIT-317BF9.svg
[NPM_INFO_IMG]: http://nodei.co/npm/cloudcmd.png
[NPMURL]: https://npmjs.org/package/cloudcmd "npm"
[BuildStatusURL]: http://travis-ci.org/coderaiser/cloudcmd "Build Status"
[BuildStatusURL]: https://travis-ci.org/coderaiser/cloudcmd "Build Status"
[DependencyStatusURL]: https://gemnasium.com/coderaiser/cloudcmd "Dependency Status"
[FlattrURL]: https://flattr.com/submit/auto?user_id=coderaiser&url=github.com/coderaiser/cloudcmd&title=cloudcmd&language=&tags=github&category=software "flattr"
[LicenseURL]: https://tldrlegal.com/license/mit-license "MIT License"
[MainURL]: http://cloudcmd.io "Main"
[BlogURL]: http://blog.cloudcmd.io "Blog"
[IOURL]: http://io.cloudcmd.io "IO"
@ -19,53 +21,32 @@ Cloud Commander v0.8.1 [![NPM version][NPMIMGURL]][NPMURL] [![Dependency Status]
[JitSu_LIVE_IMG]: http://status-ok.cloudcmd.io/host/cloudcmd.jit.su/fs?json "JitSu"
[HEROKU_LIVE_IMG]: http://status-ok.cloudcmd.io/host/cloudcmd.herokuapp.com/fs?json "Heroku"
**Cloud Commander** - cloud file manager with console and editor.
**Cloud Commander** - cloud file manager with console and editor. Will help you: **create**, **edit**, **move** and **delete files** and **folders** in your favorite browser from any computer. File manager has two parts:
- **client** (with nice and simple interface)
- **server** (based on Node.js).
![Cloud Commander](/img/logo/cloudcmd.png "Cloud Commander")
[![Flattr][FlattrIMGURL]][FlattrURL]
Benefits
---------------
- Open Source.
- Open Source (**MIT License**).
- Has 2 classic ortodox panels.
- Works on Windows, Linux and Mac OS.
- Could be used local or remotly.
- Has nice console and editor.
- Wrote on JavaScript/Node.js.
- Works in browser.
Install
---------------
[![NPM_INFO][NPM_INFO_IMG]][NPMURL]
Installing **Cloud Commander** is very simple.
All you need is
The installation of file manager is very simple.
- install [node.js](http://nodejs.org/ "node.js")
- [download](https://github.com/coderaiser/cloudcmd/archive/master.zip)
and unpack or just clone repository from github:
- install [node.js](http://nodejs.org/ "node.js") if you still have not.
- install ```cloudcmd``` via ```npm``` with one simple command.
```
git clone git://github.com/coderaiser/cloudcmd.git
cd cloudcmd
npm install
node cloudcmd
```
or install in npm:
```
npm install cloudcmd -g
cloudcmd
```
Additional modules
---------------
**Cloud Commander** could work without any modules installed.
But for console, minification, file system operations etc, recommended
install additional modules with next commnad (type in **Cloud Commander**'s directory):
npm install
![NPM_INFO][NPM_INFO_IMG]
Hot keys
---------------
@ -77,7 +58,7 @@ Hot keys
- **F5** - copy
- **F6** - rename/move
- **F7** - new dir
- **F7** + **shift** = new file
- **F7** + **shift** - new file
- **F8, Delete** - remove current file
- **F9** - menu
- **F10** - config
@ -97,7 +78,8 @@ Hot keys
- **Home** - to begin of list
- **End** - to end of list
- **Shift + Delete** - remove without prompt
- **Insert** - select current file
- **Space** - select current file (and show size of directory)
- **Insert** - select current file (and move to next)
- **Shift + F10** - context menu
- **~** - console
- **Ctrl + Click** - open file on new tab
@ -340,6 +322,7 @@ Additional modules list
To extend capabilities of file manager next modules used:
- [Ace] [AceURL]
- [Minify] [MinifyURL]
- [FancyBox] [FancyBoxURL]
- [jQuery-contextMenu] [jQuery-contextMenuURL]
- [jq-console] [jq-consoleURL]
@ -351,6 +334,7 @@ To extend capabilities of file manager next modules used:
- [fs-extra] [fs-extraURL]
[AceURL]: http://ace.ajax.org/ "Ace"
[MinifyURL]: http://coderaiser.github.io/minify "Minify"
[FancyBoxURL]: //github.com/fancyapps/fancyBox "FancyBox"
[jQuery-contextMenuURL]: //github.com/medialize/jQuery-contextMenu "jQuery-contextMenu"
[jq-consoleURL]: //github.com/replit/jq-console "jq-console"
@ -379,6 +363,7 @@ so to get it you should type a couple more commands:
Version history
---------------
- *2014.03.03*, **[v0.8.2](//github.com/cloudcmd/archive/raw/master/cloudcmd-v0.8.2.zip)**
- *2014.02.13*, **[v0.8.1](//github.com/cloudcmd/archive/raw/master/cloudcmd-v0.8.1.zip)**
- *2014.02.13*, **[v0.8.0](//github.com/cloudcmd/archive/raw/master/cloudcmd-v0.8.0.zip)**
- *2013.12.09*, **[v0.7.0](//github.com/cloudcmd/archive/raw/master/cloudcmd-v0.7.0.zip)**
@ -398,10 +383,6 @@ Version history
- *2012.07.11*, **[v0.1.1](//github.com/cloudcmd/archive/raw/master/cloudcmd-v0.1.1.zip)**
- *2012.07.09*, **[v0.1.0](//github.com/cloudcmd/archive/raw/master/cloudcmd-v0.1.0.zip)**
License
---------------
MIT [license](LICENSE "license").
Special Thanks
---------------

View file

@ -1,15 +1,17 @@
Cloud Commander v0.8.1 [![NPM version][NPMIMGURL]][NPMURL] [![Dependency Status][DependencyStatusIMGURL]][DependencyStatusURL] [![Build Status][BuildStatusIMGURL]][BuildStatusURL]
Cloud Commander v0.8.2 [![NPM version][NPMIMGURL]][NPMURL] [![Dependency Status][DependencyStatusIMGURL]][DependencyStatusURL] [![Build Status][BuildStatusIMGURL]][BuildStatusURL] [![License][LicenseIMGURL]][LicenseURL] [![Flattr][FlattrIMGURL]][FlattrURL]
===============
###[Main][MainURL] [Blog][BlogURL] Live(![IO][IO_LIVE_IMG] [IO][IOURL], ![JitSu][JitSu_LIVE_IMG] [JitSu][JitSuURL], ![Heroku][Heroku_LIVE_IMG] [Heroku][HerokuURL])
[NPMIMGURL]: https://badge.fury.io/js/cloudcmd.png
[BuildStatusIMGURL]: https://secure.travis-ci.org/coderaiser/cloudcmd.png?branch=master
[NPMIMGURL]: https://img.shields.io/npm/v/cloudcmd.svg
[BuildStatusIMGURL]: https://api.travis-ci.org/coderaiser/cloudcmd.png?branch=dev
[DependencyStatusIMGURL]: https://gemnasium.com/coderaiser/cloudcmd.png
[FlattrIMGURL]: http://api.flattr.com/button/flattr-badge-large.png
[NPM_INFO_IMG]: https://nodei.co/npm/cloudcmd.png?downloads=true&&stars
[FlattrIMGURL]: https://img.shields.io/badge/flattr-donate-317BF9.svg
[LicenseIMGURL]: https://img.shields.io/badge/license-MIT-317BF9.svg
[NPM_INFO_IMG]: https://nodei.co/npm/cloudcmd.png
[NPMURL]: https://npmjs.org/package/cloudcmd "npm"
[BuildStatusURL]: http://travis-ci.org/coderaiser/cloudcmd "Build Status"
[BuildStatusURL]: https://travis-ci.org/coderaiser/cloudcmd "Build Status"
[DependencyStatusURL]: https://gemnasium.com/coderaiser/cloudcmd "Dependency Status"
[FlattrURL]: https://flattr.com/submit/auto?user_id=coderaiser&url=github.com/coderaiser/cloudcmd&title=cloudcmd&language=&tags=github&category=software "flattr"
[LicenseURL]: https://tldrlegal.com/license/mit-license "MIT License"
[MainURL]: http://cloudcmd.io "Main"
[BlogURL]: http://blog.cloudcmd.io "Blog"
[IOURL]: http://io.cloudcmd.io "IO"
@ -21,6 +23,4 @@ Cloud Commander v0.8.1 [![NPM version][NPMIMGURL]][NPMURL] [![Dependency Status]
**Cloud Commander** - cloud file manager with console and editor.
![Cloud Commander](/img/logo/cloudcmd.png "Cloud Commander")
[![Flattr][FlattrIMGURL]][FlattrURL]
![Cloud Commander](http://cloudcmd.io/img/logo/cloudcmd.png "Cloud Commander")

View file

@ -22,16 +22,17 @@
Minify = main.minify,
Config = main.config,
INDEX_PATH = HTMLDIR + 'index.html',
CONFIG_PATH = JSONDIR + 'config.json',
KEY = DIR + 'ssl/ssl.key',
KEY = DIR + 'ssl/ssl.key',
CERT = DIR + 'ssl/ssl.crt',
FILE_TMPL = HTMLDIR + 'file.html',
PANEL_TMPL = HTMLDIR + 'panel.html',
PATH_TMPL = HTMLDIR + 'path.html',
LINK_TMPL = HTMLDIR + 'link.html',
HTML_FS_DIR = HTMLDIR + 'fs/',
INDEX_PATH = HTML_FS_DIR + 'index.html',
FILE_TMPL = HTML_FS_DIR + 'file.html',
PANEL_TMPL = HTML_FS_DIR + 'panel.html',
PATH_TMPL = HTML_FS_DIR + 'path.html',
LINK_TMPL = HTML_FS_DIR + 'link.html',
FileTemplate, PanelTemplate, PathTemplate, LinkTemplate,
@ -83,29 +84,29 @@
});
return data;
}
/**
* init and process of appcache if it allowed in config
*/
function appCacheProcessing() {
var lFONT_REMOTE = '//themes.googleusercontent.com/static/fonts/droidsansmono/v4/ns-m2xQYezAtqh7ai59hJUYuTAAIFFn5GTWtryCmBQ4.woff',
lFONT_LOCAL = './font/DroidSansMono.woff',
lJQUERY_REMOTE = '//ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js',
lJQUERY_LOCAL = './lib/client/jquery.js',
lFiles = [{}, {}];
var FONT_REMOTE = '//themes.googleusercontent.com/static/fonts/droidsansmono/v4/ns-m2xQYezAtqh7ai59hJUYuTAAIFFn5GTWtryCmBQ4.woff',
FONT_LOCAL = './font/DroidSansMono.woff',
JQUERY_REMOTE = '//ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js',
JQUERY_LOCAL = './lib/client/jquery.js',
files = [{}, {}];
lFiles[0][lFONT_REMOTE] = lFONT_LOCAL;
lFiles[1][lJQUERY_REMOTE] = lJQUERY_LOCAL;
files[0][FONT_REMOTE] = FONT_LOCAL;
files[1][JQUERY_REMOTE] = JQUERY_LOCAL;
AppCache.addFiles(lFiles);
AppCache.addFiles(files);
AppCache.createManifest();
}
function init() {
var lServerDir, lArg, lParams, lFiles;
var serverDir, params, filesList, isContain, argvFirst,
argv = process.argv;
if (update)
update.get();
@ -115,80 +116,80 @@
* (usually /) to it.
* argv[1] - is always script name
*/
lServerDir = path.dirname(process.argv[1]) + '/';
serverDir = path.dirname(argv[1]) + '/';
if (DIR !== lServerDir) {
if (DIR !== serverDir) {
Util.log('current dir: ' + DIR);
process.chdir(lServerDir);
process.chdir(serverDir);
}
Util.log('server dir: ' + lServerDir);
Util.log('server dir: ' + serverDir);
/* if command line parameter testing resolved
* setting config to testing, so server
* not created, just init and
* all logs writed to screen */
lArg = process.argv;
lArg = lArg[lArg.length - 1];
argvFirst = argv[argv.length - 1];
isContain = Util.isContainStr(argvFirst, 'test');
if ( lArg === 'test' || lArg === 'test\r') {
Util.log(process.argv);
if (isContain) {
Util.log(argv);
Config.server = false;
}
if (Config.logs) {
Util.log('log param setted up in config.json\n' +
'from now all logs will be writed to log.txt');
writeLogsToFile();
}
lParams = {
params = {
appcache : appCacheProcessing,
rest : main.rest,
route : route
},
};
lFiles = [FILE_TMPL, PANEL_TMPL, PATH_TMPL, LINK_TMPL];
filesList = [FILE_TMPL, PANEL_TMPL, PATH_TMPL, LINK_TMPL];
if (Config.ssl)
lFiles.push(KEY, CERT);
filesList.push(KEY, CERT);
files.read(lFiles, 'utf-8', function(pErrors, pFiles) {
if (pErrors)
Util.log(pErrors);
files.read(filesList, 'utf-8', function(errors, files) {
if (errors)
Util.log(errors);
else {
FileTemplate = pFiles[FILE_TMPL];
PanelTemplate = pFiles[PANEL_TMPL];
PathTemplate = pFiles[PATH_TMPL];
LinkTemplate = pFiles[LINK_TMPL];
FileTemplate = files[FILE_TMPL];
PanelTemplate = files[PANEL_TMPL];
PathTemplate = files[PATH_TMPL];
LinkTemplate = files[LINK_TMPL];
if (Config.ssl)
lParams.ssl = {
key : pFiles[KEY],
cert : pFiles[CERT]
params.ssl = {
key : files[KEY],
cert : files[CERT]
};
server.start(lParams);
server.start(params);
}
});
}
function readConfig(callback) {
fs.readFile(CONFIG_PATH, 'utf8', function(error, data) {
var msg, status, readed;
var status, json, msg;
if (error)
status = 'error';
status = 'error';
else {
status = 'ok';
readed = Util.parseJSON(data);
main.config = Config = readed;
status = 'ok';
json = Util.parseJSON(data);
main.config = Config = json;
}
msg = CloudFunc.formatMsg('read', 'config', status);
Util.log(msg);
msg = CloudFunc.formatMsg('read', 'config', status);
Util.log(msg);
Util.exec(callback);
});
}
@ -197,7 +198,7 @@
* routing of server queries
*/
function route(request, response, callback) {
var ret, name, params, isAuth, isFS;
var ret, name, params, isAuth, isFS, query;
if (request && response) {
ret = true;
@ -216,9 +217,20 @@
params.name = main.HTMLDIR + name + '.html';
main.sendFile(params);
} else if (isFS)
sendContent(params);
else {
} else if (isFS) {
query = main.getQuery(params.request),
sendContent(name, query, function(name, error, data, isFile) {
if (error)
main.sendError(params, error);
else if (isFile) {
params.name = name;
main.sendFile(params);
} else {
params.name = name;
main.sendResponse(params, data, true);
}
});
} else {
ret = false;
Util.exec(callback);
}
@ -227,74 +239,59 @@
return ret;
}
function sendContent(pParams) {
var p, lRet = main.checkParams(pParams);
function sendContent(name, query, callback) {
name = Util.removeStrOneTime(name, CloudFunc.FS) || main.SLASH;
if (lRet) {
p = pParams;
p.name = Util.removeStrOneTime(p.name, CloudFunc.FS) || main.SLASH;
fs.stat(name, function(error, stat) {
var func = Util.retExec(callback, name);
fs.stat(p.name, function(error, stat) {
if (error)
main.sendError(pParams, error);
else
if (stat.isDirectory())
processContent(pParams);
else
main.sendFile(pParams);
});
}
return lRet;
}
function processContent(params) {
var p = params,
ret = main.checkParams(params);
if (ret)
main.commander.getDirContent(p.name, function(error, json) {
var query, isJSON;
if (error)
main.sendError(params, error);
if (error)
func(error);
else
if (!stat.isDirectory())
func(error, null, true);
else {
query = main.getQuery(p.request);
isJSON = Util.isContainStr(query, 'json');
if (!isJSON)
readIndex(json, params);
else {
p.data = Util.stringifyJSON(json);
p.name +='.json';
main.sendResponse(params, null, true);
}
processContent(name, query, callback);
}
});
});
}
function readIndex(pJSON, params) {
var p = params;
function processContent(name, query, callback) {
main.commander.getDirContent(name, function(error, json) {
var data, name,
isJSON = Util.isContainStr(query, 'json');
if (!isJSON && !error)
readIndex(json, Util.retExec(callback, INDEX_PATH));
else {
if (!error) {
data = Util.stringifyJSON(json);
name +='.json';
}
Util.exec(callback, name, error, data);
}
});
}
function readIndex(json, callback) {
Util.ifExec(!Minify, function(params) {
var name = params && params.name;
fs.readFile(name || INDEX_PATH, 'utf8', function(error, template) {
var panel,
var panel, data,
config = main.config,
minify = config.minify;
if (error)
main.sendError(p, error);
else {
p.name = INDEX_PATH,
panel = CloudFunc.buildFromJSON(pJSON, FileTemplate, PathTemplate, LinkTemplate),
main.sendResponse(p, indexProcessing({
if (!error) {
panel = CloudFunc.buildFromJSON(json, FileTemplate, PathTemplate, LinkTemplate),
data = indexProcessing({
panel : panel,
data : template,
}), true);
});
}
Util.exec(callback, error, data);
});
}, function(callback) {
Minify.optimize(INDEX_PATH, {

View file

@ -22,11 +22,12 @@
}
html {
height: 100%;
height: 94%;
}
body {
height: 95%;
width: 100%;
font:16px "Droid Sans Mono";
background-color:white;
}
@ -85,12 +86,13 @@ body {
}
.loading {
position : relative;
top : 1px;
display : inline-block;
width : 15px;
height : 14.8px;
background : url(/img/spinner.gif);
position : relative;
top : 2px;
display : inline-block;
width : 16px;
height : 16px;
background : url(/img/spinner.gif);
vertical-align : top;
}
.refresh-icon {
@ -103,6 +105,7 @@ body {
.cmd-button {
width: 5%;
height: 30px;
margin: 20px 2px 0 2px;
color: #222;
background-color: white;
@ -164,7 +167,8 @@ body {
}
.fm {
height: 85%;
margin: 26px 26px 0 26px;
width: 97%;
margin: 26px auto 0 auto;
}
.fm-header {
font-weight: bold;
@ -188,9 +192,8 @@ body {
}
.panel {
width: 46%;
height: 90%;
padding: 20px;
margin: 0;
height: 97%;
padding: 1%;
border: 1.5px solid;
border-color: rgb(49, 123, 249);
border-color: rgba(49, 123, 249, .40);
@ -264,7 +267,22 @@ a:hover, a:active {
* друг-под-другом
*/
/* responsive design */
@media only screen and (max-height: 800px) {
.fm {
height: 74%;
}
.files {
height: 85%;
}
}
@media only screen and (max-width: 600px) {
.panel {
font-size: 26px;
}
/* текущий файл под курсором */
.current-file {
background-color: rgb(49, 123, 249);
@ -272,25 +290,18 @@ a:hover, a:active {
color:white;
}
/* делаем иконки под курсом белыми*/
.current-file > .mini-icon{
.current-file a {
color:white;
}
.current-file > .text-file::before {
.current-file .text-file::before {
color:white;
}
.fm-header {
display:none;
}
/* меняем иконки на шрифтовые*/
.mini-icon {
color : rgb(246, 224, 124);
color : rgba(246, 224, 124, 0.56);
font : 16px 'Fontello';
width : 6%;
margin-left : 10px;
float : left;
background-image: none;
}
@ -300,8 +311,8 @@ a:hover, a:active {
.name {
float: none;
width: 100%;
font-size: 18px;
width: 90%;
display: inline-block;
}
.directory::before {
@ -315,9 +326,9 @@ a:hover, a:active {
.text-file {
background-image:none;
}
/* убираем заголовок*/
.fm_header {
.fm-header {
display:none;
}
@ -341,7 +352,7 @@ a:hover, a:active {
@media only screen and (max-width: 1155px) {
.panel {
width:94%;
width:97%;
}
/* если правая панель не помещаеться - прячем её */
.panel-right, .cmd-button#f5, .cmd-button#f6 {

BIN
favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View file

@ -7,27 +7,55 @@
<meta content="width=device-width,initial-scale=1" name="viewport" />
<!-- chrome frame -->
<meta http-equiv="X-UA-Compatible" content=" chrome=1" />
<link href=/img/favicon/favicon.png rel=icon type=image/png />
<link rel="icon" href="/favicon.ico" />
<title>{{ title }}</title>
<link rel=stylesheet href=/join/css/reset.css:css/style.css:css/icons.css>
<noscript>
<style>
.path-icon, .keyspanel {
display: none;
}
.links {
margin-left: 16px;
}
.fm {
height: 100%;
}
.panel-right {
display: none;
}
.panel-left {
width: 97%;
}
.name a:hover {
cursor: pointer;
}
</style>
</noscript>
</head>
<body>
<div class=fm>{{ fm }}</div>
<div class="keyspanel">
<button id=f1 class="cmd-button reduce-text icon-help" title="help">F1</button>
<button id=f2 class="cmd-button reduce-text icon-rename" title="rename">F2</button>
<button id=f3 class="cmd-button reduce-text icon-view" title="view">F3</button>
<button id=f4 class="cmd-button reduce-text icon-edit " title="edit">F4</button>
<button id=f5 class="cmd-button reduce-text icon-copy" title="copy">F5</button>
<button id=f6 class="cmd-button reduce-text icon-move" title="move">F6</button>
<button id=f7 class="cmd-button reduce-text icon-directory" title="make directory">F7</button>
<button id=f8 class="cmd-button reduce-text icon-delete" title="delete">F8</button>
<button id=f9 class="cmd-button reduce-text icon-menu" title="menu">F9</button>
<button id=f10 class="cmd-button reduce-text icon-config" title="config">F10</button>
<button id=~ class="cmd-button reduce-text icon-console" title="console">~</button>
<button id=contact class="cmd-button reduce-text icon-contact" title="contact"></button>
<button id=f1 class="cmd-button reduce-text icon-help" title="help" >F1</button>
<button id=f2 class="cmd-button reduce-text icon-rename" title="rename" >F2</button>
<button id=f3 class="cmd-button reduce-text icon-view" title="view" >F3</button>
<button id=f4 class="cmd-button reduce-text icon-edit " title="edit" >F4</button>
<button id=f5 class="cmd-button reduce-text icon-copy" title="copy" >F5</button>
<button id=f6 class="cmd-button reduce-text icon-move" title="move" >F6</button>
<button id=f7 class="cmd-button reduce-text icon-directory" title="make directory" >F7</button>
<button id=f8 class="cmd-button reduce-text icon-delete" title="delete" >F8</button>
<button id=f9 class="cmd-button reduce-text icon-menu" title="menu" >F9</button>
<button id=f10 class="cmd-button reduce-text icon-config" title="config" >F10</button>
<button id=~ class="cmd-button reduce-text icon-console" title="console" >~</button>
<button id=contact class="cmd-button reduce-text icon-contact" title="contact" ></button>
</div>
<script>
!(function() {
@ -42,6 +70,7 @@
client + 'dom.js',
client + 'loader.js',
client + 'notify.js',
client + 'storage.js',
lib + 'client.js',
client + 'listeners.js',
client + 'key.js'

1
html/fs/path.html Normal file
View file

@ -0,0 +1 @@
<div data="js-path" class="reduce-text" title="{{ fullPath }}"><span class="path-icon clear-storage" title="clear storage (Ctrl+D)"></span><span class="path-icon refresh-icon" title="refresh (Ctrl+R)"><a href="{{ link }}"></a></span><span class=links>{{ path }}</span></div>

View file

@ -1 +0,0 @@
<div id="js-path" class="reduce-text" title="{{ fullPath }}"><span class="path-icon clear-storage" title="clear storage (Ctrl+D)"></span><span class="path-icon refresh-icon" title="refresh (Ctrl+R)"><a href="{{ link }}"></a></span><span class=links>{{ path }}</span></div>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 495 B

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 337 B

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Before After
Before After

View file

@ -56,7 +56,7 @@
".hh": "text/x-c",
".htm": "text/html",
".html": "text/html",
".ico": "image/vnd.microsoft.icon",
".ico": "image/x-icon",
".ics": "text/calendar",
".ifb": "text/calendar",
".iso": "application/octet-stream",

View file

@ -11,6 +11,10 @@ var Util, DOM, CloudFunc;
function CloudCmdProto(Util, DOM, CloudFunc) {
var Key, Config, Modules, Extensions,
FileTemplate, PathTemplate, LinkTemplate, Listeners,
DIR_HTML = '/html/',
DIR_HTML_FS = DIR_HTML + 'fs/',
DIR_JSON = '/json/',
Images = DOM.Images,
Info = DOM.CurrentInfo,
CloudCmd = this,
@ -18,13 +22,11 @@ var Util, DOM, CloudFunc;
this.LIBDIR = '/lib/';
this.LIBDIRCLIENT = '/lib/client/';
this.JSONDIR = '/json/';
this.HTMLDIR = '/html/';
this.MIN_ONE_PANEL_WIDTH = 1155;
this.OLD_BROWSER = false;
this.HOST = (function() {
var lLocation = document.location;
return lLocation.protocol + '//' + lLocation.host;
var location = document.location;
return location.protocol + '//' + location.host;
})();
/**
@ -34,25 +36,31 @@ var Util, DOM, CloudFunc;
* @param pLink - ссылка
* @param pNeedRefresh - необходимость обязательной загрузки данных с сервера
*/
this.loadDir = function(pLink, pNeedRefresh) {
return function(pEvent) {
/* показываем гиф загрузки возле пути папки сверху
* ctrl+r нажата? */
this.loadDir = function(paramLink, needRefresh) {
return function(event) {
var link,
currentLink = DOM.getCurrentLink(),
href = currentLink.href;
var lCurrentLink = DOM.getCurrentLink(),
lHref = lCurrentLink.href,
lLink = pLink || Util.removeStr(lHref, CloudCmd.HOST);
if (paramLink)
link = paramLink;
else
link = Util.removeStr(href, CloudCmd.HOST);
lLink += '?json';
link += '?json';
if (lLink || lCurrentLink.target !== '_blank') {
Images.showLoad(pNeedRefresh ? {top:true} : null);
if (link || currentLink.target !== '_blank') {
Images.showLoad(!needRefresh ? null: {
top:true
});
/* загружаем содержимое каталога */
CloudCmd.ajaxLoad(lLink, { refresh: pNeedRefresh });
CloudCmd.ajaxLoad(link, {
refresh: needRefresh
});
}
DOM.preventDefault(pEvent);
DOM.preventDefault(event);
};
};
@ -63,15 +71,15 @@ var Util, DOM, CloudFunc;
* в верх по файловой структуре
* @param pDirName - имя каталога с которого мы пришли
*/
function currentToParent(pDirName) {
var lRootDir;
function currentToParent(dirName) {
var rootDir;
/* убираем слэш с имени каталога */
pDirName = Util.removeStr(pDirName, '/');
lRootDir = DOM.getCurrentFileByName(pDirName);
dirName = Util.removeStr(dirName, '/');
rootDir = DOM.getCurrentFileByName(dirName);
if (lRootDir) {
DOM.setCurrentFile(lRootDir);
DOM.scrollIntoViewIfNeeded(lRootDir, true);
if (rootDir) {
DOM.setCurrentFile(rootDir);
DOM.scrollIntoViewIfNeeded(rootDir, true);
}
}
@ -79,50 +87,51 @@ var Util, DOM, CloudFunc;
* function load modules
* @pParams = {name, path, func, dobefore, arg}
*/
function loadModule(pParams) {
var lName, lPath, lFunc, lDoBefore, lSlash, lAfterSlash,
function loadModule(params) {
var name, path, func, doBefore, slash, afterSlash,
isContain;
if (pParams) {
lName = pParams.name,
lPath = pParams.path,
lFunc = pParams.func,
lDoBefore = pParams.dobefore;
if (params) {
name = params.name,
path = params.path,
func = params.func,
doBefore = params.dobefore;
if (Util.isString(pParams))
lPath = pParams;
if (Util.isString(params))
path = params;
if (lPath && !lName) {
lName = Util.getStrBigFirst(lPath);
lName = Util.removeStr(lName, '.js');
if (path && !name) {
name = Util.getStrBigFirst(path);
name = Util.removeStr(name, '.js');
lSlash = lName.indexOf('/');
if (lSlash > 0) {
lAfterSlash = lName.substr(lSlash);
lName = Util.removeStr(lName, lAfterSlash);
slash = name.indexOf('/');
if (slash > 0) {
afterSlash = name.substr(slash);
name = Util.removeStr(name, afterSlash);
}
}
isContain = Util.isContainStr(lPath, '.js');
if (!isContain)
lPath += '.js';
isContain = Util.isContainStr(path, '.js');
if (!CloudCmd[lName]) {
CloudCmd[lName] = function(pArg) {
var path = CloudCmd.LIBDIRCLIENT + lPath;
if (!isContain)
path += '.js';
if (!CloudCmd[name]) {
CloudCmd[name] = function(arg) {
path = CloudCmd.LIBDIRCLIENT + path;
Util.exec(lDoBefore);
Util.exec(doBefore);
return DOM.jsload(path, lFunc ||
return DOM.jsload(path, func ||
function() {
var Proto = CloudCmd[lName];
var Proto = CloudCmd[name];
if (Util.isFunction(Proto))
CloudCmd[lName] = new Proto(pArg);
CloudCmd[name] = new Proto(arg);
});
};
CloudCmd[lName].show = CloudCmd[lName];
CloudCmd[name].show = CloudCmd[name];
}
}
}
@ -132,49 +141,50 @@ var Util, DOM, CloudFunc;
* инициализации
*/
this.init = function() {
var lCallBack, lFunc;
lCallBack = function() {
Util.loadOnLoad([
initModules,
baseInit,
Util.bind(CloudCmd.route, location.hash)
]);
},
lFunc = function(pCallBack) {
CloudCmd.OLD_BROWSER = true;
var lSrc = CloudCmd.LIBDIRCLIENT + 'polyfill.js';
var callback = function() {
Util.loadOnLoad([
initModules,
baseInit,
Util.bind(CloudCmd.route, location.hash)
]);
},
DOM.jqueryLoad(
DOM.retJSLoad(lSrc, pCallBack)
);
};
func = function(callBack) {
var src = CloudCmd.LIBDIRCLIENT + 'polyfill.js';
CloudCmd.OLD_BROWSER = true;
DOM.jqueryLoad(function() {
DOM.jsload(src, callback);
});
};
Util.ifExec(document.body.scrollIntoViewIfNeeded, lCallBack, lFunc);
Util.ifExec(document.body.scrollIntoViewIfNeeded, callback, func);
};
this.route = function(pPath) {
var lQuery, lModule, lFile, lCurrent, lMsg;
this.route = function(path) {
var query, module, file, current, msg;
if (pPath.length > 0) {
lQuery = pPath.split('/');
if (path.length > 0) {
query = path.split('/');
if (lQuery.length > 0) {
lModule = Util.getStrBigFirst(lQuery[1]);
lFile = lQuery[2];
lCurrent = DOM.getCurrentFileByName(lFile);
if (lFile && !lCurrent) {
lMsg = CloudFunc.formatMsg('set current file', lFile, 'error');
Util.log(lMsg);
if (query.length > 0) {
module = Util.getStrBigFirst(query[1]);
file = query[2];
current = DOM.getCurrentFileByName(file);
if (file && !current) {
msg = CloudFunc.formatMsg('set current file', file, 'error');
Util.log(msg);
} else {
DOM.setCurrentFile(lCurrent);
CloudCmd.execFromModule(lModule, 'show');
DOM.setCurrentFile(current);
CloudCmd.execFromModule(module, 'show');
}
}
}
};
function initModules(pCallBack) {
function initModules(callback) {
Util.ifExec(CloudCmd.Key, function() {
Key = new CloudCmd.Key();
CloudCmd.Key = Key;
@ -187,19 +197,15 @@ var Util, DOM, CloudFunc;
});
});
CloudCmd.getModules(function(pModules) {
pModules = pModules || [];
CloudCmd.getModules(function(modules) {
var i, n, module, storageObj, mod, name, path,
STORAGE = 'storage',
showLoadFunc = Util.bind(Images.showLoad, {
top:true
}),
STORAGE = 'storage',
showLoad = Images.showLoad.bind(Images),
doBefore = {
'edit' : showLoadFunc,
'view' : showLoadFunc,
'menu' : showLoadFunc
doBefore = {
'edit' : showLoad,
'menu' : showLoad,
'storage/_filepicker' : showLoad
},
load = function(name, path, func) {
@ -210,25 +216,28 @@ var Util, DOM, CloudFunc;
});
};
for (i = 0, n = pModules.length; i < n ; i++) {
module = pModules[i];
if (!modules)
modules = [];
n = modules.length;
for (i = 0; i < n ; i++) {
module = modules[i];
if (Util.isString(module))
load(null, module, doBefore[module]);
}
storageObj = Util.findObjByNameInArr(pModules, STORAGE),
storageObj = Util.findObjByNameInArr(modules, STORAGE),
mod = Util.getNamesFromObjArray(storageObj);
for (i = 0, n = mod.length; i < n; i++) {
name = mod[i],
path = STORAGE + '/_' + name.toLowerCase();
load(name, path);
load(name, path, doBefore[path]);
}
Util.exec(pCallBack);
Util.exec(callback);
});
}
@ -263,9 +272,13 @@ var Util, DOM, CloudFunc;
dirPath = CloudFunc.rmLastSlash(dirPath) || '/';
if (!Storage.get(dirPath))
Storage.set(dirPath, getJSONfromFileTable());
Storage.get(dirPath, function(data) {
if (!data) {
data = getJSONfromFileTable();
Storage.set(dirPath, data);
}
});
});
Util.exec(CloudCmd.Key);
Util.exec(pCallBack);
@ -289,35 +302,39 @@ var Util, DOM, CloudFunc;
}
this.setConfig = function(config) { Config = config; };
this.getConfig = getSystemFile(Config, CloudCmd.JSONDIR + 'config.json');
this.getModules = getSystemFile(Modules, CloudCmd.JSONDIR + 'modules.json');
this.getExt = getSystemFile(Extensions, CloudCmd.JSONDIR + 'ext.json');
this.getFileTemplate = getSystemFile(FileTemplate, CloudCmd.HTMLDIR + 'file.html');
this.getPathTemplate = getSystemFile(PathTemplate, CloudCmd.HTMLDIR + 'path.html');
this.getLinkTemplate = getSystemFile(PathTemplate, CloudCmd.HTMLDIR + 'link.html');
this.getConfig = getSystemFile(Config, DIR_JSON + 'config.json');
this.getModules = getSystemFile(Modules, DIR_JSON + 'modules.json');
this.getExt = getSystemFile(Extensions, DIR_JSON + 'ext.json');
this.getFileTemplate = getSystemFile(FileTemplate, DIR_HTML_FS + 'file.html');
this.getPathTemplate = getSystemFile(PathTemplate, DIR_HTML_FS + 'path.html');
this.getLinkTemplate = getSystemFile(PathTemplate, DIR_HTML_FS + 'link.html');
this.execFromModule = function(pModuleName, pFuncName, pParams) {
var lObject = CloudCmd[pModuleName];
Util.ifExec(Util.isObject(lObject),
this.execFromModule = function(moduleName, funcName, params) {
var obj = CloudCmd[moduleName],
isObj = Util.isObject(obj);
Util.ifExec(isObj,
function() {
var lObj = CloudCmd[pModuleName];
Util.exec( lObj[pFuncName], pParams);
var obj = CloudCmd[moduleName],
func = obj[funcName];
Util.exec(func, params);
},
function(pCallBack) {
Util.exec(lObject, pCallBack);
function(callback) {
Util.exec(obj, callback);
});
};
this.refresh = function(pCurrent) {
var lNEEDREFRESH = true,
lPanel = pCurrent && pCurrent.parentElement,
lPath = DOM.getCurrentDirPath(lPanel),
lLink = CloudFunc.FS + lPath,
lNotSlashlLink = CloudFunc.rmLastSlash(lLink),
lLoad = CloudCmd.loadDir(lNotSlashlLink, lNEEDREFRESH);
this.refresh = function(current) {
var NEEDREFRESH = true,
panel = current && current.parentElement,
path = DOM.getCurrentDirPath(panel),
link = CloudFunc.FS + path,
notSlashlLink = CloudFunc.rmLastSlash(link),
load = CloudCmd.loadDir(notSlashlLink, NEEDREFRESH);
lLoad();
load();
};
/**
@ -327,28 +344,33 @@ var Util, DOM, CloudFunc;
* @param pOptions
* { refresh, nohistory } - необходимость обновить данные о каталоге
*/
this.ajaxLoad = function(pPath, pOptions) {
if (!pOptions)
pOptions = {};
this.ajaxLoad = function(path, options) {
var SLASH = '/',
dirPath = DOM.getCurrentDirPath(),
fsPath = decodeURI(path),
noJSONPath = Util.removeStr(fsPath, '?json' ),
cleanPath = Util.removeStrOneTime(noJSONPath, CloudFunc.FS) || SLASH,
setTitle = function() {
var title;
dirPath = CloudFunc.rmLastSlash(dirPath) || '/';
if (dirPath !== cleanPath) {
if (!options.nohistory)
DOM.setHistory(noJSONPath, null, noJSONPath);
title = CloudFunc.getTitle(cleanPath);
DOM.setTitle(title);
}
};
/* Отображаем красивые пути */
var lSLASH = '/',
title = CloudFunc.getTitle(lCleanPath),
lFSPath = decodeURI(pPath),
lNOJSPath = Util.removeStr( lFSPath, '?json' ),
lCleanPath = Util.removeStrOneTime( lNOJSPath, CloudFunc.FS ) || lSLASH,
lOldURL = window.location.pathname;
if (!options)
options = {};
if (lCleanPath === lSLASH)
lNOJSPath = lSLASH;
if (cleanPath === SLASH)
noJSONPath = SLASH;
Util.log ('reading dir: "' + lCleanPath + '";');
if (!pOptions.nohistory)
DOM.setHistory(lNOJSPath, null, lNOJSPath);
DOM.setTitle(title);
Util.log ('reading dir: "' + cleanPath + '";');
/* если доступен localStorage и
* в нём есть нужная нам директория -
@ -357,102 +379,78 @@ var Util, DOM, CloudFunc;
* если стоит поле обязательной перезагрузки -
* перезагружаемся
*/
var lRet = pOptions.refresh;
if (!lRet) {
var lJSON = Storage.get(lCleanPath);
Storage.get(cleanPath, function(json) {
var ret = options && options.refresh;
if (lJSON) {
lJSON = Util.parseJSON(lJSON);
CloudCmd.createFileTable(lJSON);
}
else
lRet = true;
}
if (lRet)
DOM.getCurrentFileContent({
url : lFSPath,
dataType: 'json',
error : function() {
DOM.setHistory(lOldURL, null, lOldURL);
},
success : function(pData) {
CloudCmd.createFileTable(pData);
/* переводим таблицу файлов в строку, для *
* сохранения в localStorage */
var lJSON_s = Util.stringifyJSON(pData);
Util.log(lJSON_s.length);
/* если размер данных не очень бошьой *
* сохраняем их в кэше */
if (lJSON_s.length < 50000 )
Storage.set(lCleanPath, lJSON_s);
}
});
if (!ret && json) {
json = Util.parseJSON(json);
CloudCmd.createFileTable(json);
setTitle();
} else
DOM.getCurrentFileContent({
url : fsPath,
dataType : 'json',
success : function(json) {
setTitle();
CloudCmd.createFileTable(json);
Storage.set(cleanPath, json);
}
});
});
};
/**
* Функция строит файловую таблицу
* @param pJSON - данные о файлах
*/
this.createFileTable = function(pJSON) {
this.createFileTable = function(json) {
var files,
panel = DOM.getPanel(),
/* getting current element if was refresh */
lPath = DOM.getCurrentDirPath(panel),
lCurrent = DOM.getCurrentFile(),
lDir = DOM.getCurrentDirName(),
lName = DOM.getCurrentName(lCurrent),
wasRefresh = lPath === pJSON.path,
lFuncs = [
path = DOM.getCurrentDirPath(panel),
wasRefresh = path === json.path,
funcs = [
CloudCmd.getFileTemplate,
CloudCmd.getPathTemplate,
CloudCmd.getLinkTemplate
];
Util.asyncCall(lFuncs, function(pTemplate, pPathTemplate, pLinkTemplate) {
/* очищаем панель */
var n, found,
i = panel.childNodes.length;
Util.asyncCall(funcs, function(templFile, templPath, templLink) {
var n, found, varCurrent, varName, current,
dir = DOM.getCurrentDirName(),
name = DOM.getCurrentName(),
i = panel.childNodes.length;
while(i--)
panel.removeChild(panel.lastChild);
panel.innerHTML = CloudFunc.buildFromJSON(pJSON, pTemplate, pPathTemplate, pLinkTemplate);
files = DOM.getFiles(panel);
panel.innerHTML = CloudFunc.buildFromJSON(json, templFile, templPath, templLink);
files = DOM.getFiles(panel);
/* searching current file */
if (wasRefresh) {
n = files.length;
for (i = 0; i < n ; i++) {
var lVarCurrent = files[i],
lVarName = DOM.getCurrentName(lVarCurrent);
found = lVarName === lName;
varCurrent = files[i],
varName = DOM.getCurrentName(varCurrent);
found = varName === name;
if (found) {
lCurrent = files[i];
current = files[i];
break;
}
}
}
if (!found) /* .. */
lCurrent = files[0];
current = files[0];
DOM.setCurrentFile(lCurrent);
DOM.setCurrentFile(current);
Listeners.changeLinks(panel.id);
if (lName === '..' && lDir !== '/')
currentToParent(lDir);
if (name === '..' && dir !== '/')
currentToParent(dir);
});
};

View file

@ -6,19 +6,23 @@ var CloudCmd, Util, DOM;
CloudCmd.Config = ConfigProto;
function ConfigProto() {
var Loading = true,
Key = CloudCmd.Key,
Images = DOM.Images,
Events = DOM.Events,
INPUT = 'INPUT',
var Loading = true,
Key = CloudCmd.Key,
Images = DOM.Images,
Events = DOM.Events,
showLoad = Images.showLoad.bind(DOM, {
top: true
}),
INPUT = 'INPUT',
CONFIG,
TEMPLATE,
Notify = DOM.Notify,
Config = this;
Notify = DOM.Notify,
Config = this;
function init(pCallBack) {
Loading = true;
showLoad();
Util.loadOnLoad([
CloudCmd.View,
function(callback) {
@ -36,7 +40,7 @@ var CloudCmd, Util, DOM;
];
if (!Loading) {
Images.showLoad({top:true});
showLoad();
Util.asyncCall(funcs, fillTemplate);
}
};

View file

@ -20,7 +20,7 @@ var CloudCmd, Util, DOM, CloudFunc, Dialog;
};
function getImage(name) {
var id = 'image-' + name,
var id = 'js-image-' + name,
element = Images[id];
if (!element)
@ -319,6 +319,18 @@ var CloudCmd, Util, DOM, CloudFunc, Dialog;
return ret;
};
this.getByAttr = function(attribute, element) {
var ret,
selector = '[' + 'data="' + attribute + '"]';
if (!element)
element = document;
ret = element.querySelector(selector);
return ret;
};
/**
* Function search element by class name
* @param pClass - className
@ -585,78 +597,6 @@ var CloudCmd, Util, DOM, CloudFunc, Dialog;
}
}
},
StorageProto = function() {
/* приватный переключатель возможности работы с кэшем */
var StorageAllowed;
/* функция проверяет возможно ли работать с кэшем каким-либо образом */
this.isAllowed = function() {
var lRet = StorageAllowed && !!window.localStorage;
return lRet;
};
/**
* allow Storage usage
*/
this.setAllowed = function(pAllowd) {
StorageAllowed = pAllowd;
return pAllowd;
};
/** remove element */
this.remove = function(pItem) {
var lRet = this;
if (StorageAllowed)
localStorage.removeItem(pItem);
return lRet;
};
/** если доступен localStorage и
* в нём есть нужная нам директория -
* записываем данные в него
*/
this.set = function(pName, pData) {
var lRet = this;
if (StorageAllowed && pName)
localStorage.setItem(pName, pData);
return lRet;
},
/** Если доступен Storage принимаем из него данные*/
this.get = function(pName) {
var lRet;
if (StorageAllowed)
lRet = localStorage.getItem(pName);
return lRet;
},
/* get all Storage from local storage */
this.getAll = function() {
var lRet = null;
if (StorageAllowed)
lRet = localStorage;
return lRet;
};
/** функция чистит весь кэш для всех каталогов*/
this.clear = function() {
var lRet = this;
if (StorageAllowed)
localStorage.clear();
return lRet;
};
},
CmdProto = function() {
var Cmd = this,
@ -758,9 +698,8 @@ var CloudCmd, Util, DOM, CloudFunc, Dialog;
*
* @pCurrentFile
*/
this.promptDeleteSelected = function(pCurrentFile) {
var ret, type, isDir, path,
current, query, msg,
this.promptDeleteSelected = function(current) {
var ret, type, isDir, path, query, msg,
name = '',
msgAsk = 'Do you really want to delete the ',
msgSel = 'selected ',
@ -768,7 +707,7 @@ var CloudCmd, Util, DOM, CloudFunc, Dialog;
names = Cmd.getSelectedNames(files),
i, n = names && names.length;
if (!Cmd.isCurrentFile(pCurrentFile))
if (!Cmd.isCurrentFile(current))
current = DOM.getCurrentFile();
if (n > 1) {
@ -805,8 +744,9 @@ var CloudCmd, Util, DOM, CloudFunc, Dialog;
if (ret)
RESTful.delete(path, names, function() {
var dirPath = CurrentInfo.dirPath,
dir = CloudFunc.rmLastSlash(dirPath);
var Storage = DOM.Storage,
dirPath = CurrentInfo.dirPath,
dir = CloudFunc.rmLastSlash(dirPath);
if (n > 1)
DOM.deleteSelected(files);
@ -839,15 +779,16 @@ var CloudCmd, Util, DOM, CloudFunc, Dialog;
/**
* get current direcotory path
*/
this.getCurrentDirPath = function(pPanel) {
var lPanel = pPanel || this.getPanel(),
lPath = this.getById('js-path', lPanel),
lRet;
this.getCurrentDirPath = function(panel) {
var ret, path;
if (lPath)
lRet = lPath.textContent;
if (!panel)
panel = this.getPanel();
return lRet;
path = this.getByAttr('js-path', panel);
ret = path && path.textContent;
return ret;
};
/**
@ -1391,16 +1332,19 @@ var CloudCmd, Util, DOM, CloudFunc, Dialog;
/**
* set name from current (or param) file
*
* @param pCurrentFile
* @param name
* @param current
*/
this.setCurrentName = function(pName, pCurrentFile) {
var lLink = this.getCurrentLink( pCurrentFile ),
lDir = this.getCurrentDirName() + '/';
this.setCurrentName = function(name, current) {
var link = this.getCurrentLink(current),
dir = this.getCurrentDirName() + '/',
panel = DOM.getPanel();
lLink.title = lLink.textContent = pName;
lLink.href = lDir + pName;
link.title = link.textContent = name;
link.href = dir + name;
current.id = name + '(' + panel.id + ')';
return lLink;
return link;
};
/**
@ -1408,17 +1352,20 @@ var CloudCmd, Util, DOM, CloudFunc, Dialog;
*/
this.checkStorageHash = function(name, callback) {
DOM.loadCurrentHash(function(loadHash) {
var equal, error,
nameHash = name + '-hash',
storeHash = Storage.get(name + '-hash'),
isContain = Util.isContainStr(loadHash, 'error');
var Storage = DOM.Storage;
if (isContain)
error = loadHash;
else if (loadHash === storeHash)
equal = true;
Util.exec(callback, error, equal, loadHash);
Storage.get(name + '-hash', function(storeHash) {
var equal, error,
nameHash = name + '-hash',
isContain = Util.isContainStr(loadHash, 'error');
if (isContain)
error = loadHash;
else if (loadHash === storeHash)
equal = true;
Util.exec(callback, error, equal, loadHash);
});
});
};
@ -1440,6 +1387,8 @@ var CloudCmd, Util, DOM, CloudFunc, Dialog;
Util.exec(callback);
else
Util.ifExec(hash, function() {
var Storage = DOM.Storage;
Storage.set(nameHash, hash);
Storage.set(nameData, data);
@ -1463,6 +1412,7 @@ var CloudCmd, Util, DOM, CloudFunc, Dialog;
this.getDataFromStorage = function(name, callback) {
CloudCmd.getConfig(function(config) {
var data, hash,
Storage = DOM.Storage,
nameHash = name + '-hash',
nameData = name + '-data',
allowed = config.localStorage,
@ -1471,10 +1421,20 @@ var CloudCmd, Util, DOM, CloudFunc, Dialog;
if (!allowed || isDir)
Util.exec(callback);
else {
data = Storage.get(nameData);
hash = Storage.get(nameHash);
Util.asyncCall([
function(callback) {
Storage.get(nameData, function(data) {
Util.exec(callback, data);
});
},
function(callback) {
Storage.get(nameHash, function(hash) {
Util.exec(callback, hash);
});
}
], callback);
Util.exec(callback, data, hash);
}
});
};
@ -1592,50 +1552,53 @@ var CloudCmd, Util, DOM, CloudFunc, Dialog;
/**
* remove current file from file table
* @pCurrent
* @param current
*
*/
this.deleteCurrent = function(pCurrent, pNextFile, pPreviousFile, pNotSet) {
var lCurrent = pCurrent || Cmd.getCurrentFile(),
lParent = lCurrent && lCurrent.parentElement,
lName = Cmd.getCurrentName(lCurrent);
this.deleteCurrent = function(current) {
var name, next, prev, parent;
if (lCurrent && lParent && lName !== '..') {
var lNext = pNextFile || lCurrent.nextSibling,
lPrevious = pPreviousFile || lCurrent.previousSibling;
if (!current)
Cmd.getCurrentFile();
parent = current && current.parentElement;
name = Cmd.getCurrentName(current);
if (current && name !== '..') {
next = current.nextSibling,
prev = current.previousSibling;
if (!pNotSet)
if (lNext)
this.setCurrentFile(lNext);
else if (lPrevious)
this.setCurrentFile(lPrevious);
lParent.removeChild(lCurrent);
if (next)
this.setCurrentFile(next);
else if (prev)
this.setCurrentFile(prev);
parent.removeChild(current);
}
return lCurrent;
return current;
};
/**
* remove selected files from file table
* @Selected
*/
this.deleteSelected = function(pSelected) {
var lSelected = pSelected || this.getSelectedFiles();
this.deleteSelected = function(selected) {
var i, n, last, current;
if (lSelected) {
var n = lSelected.length,
lLast = n-1,
lNext = lSelected[lLast].nextSibling,
lPrev = lSelected[0].previousSibling;
if (!selected)
selected = this.getSelectedFiles();
if (selected) {
n = selected.length;
/* lSelected[0] - becouse lSelected is a link to DOM so
* when we remove 0 element, it's removed from lSelected to
*/
for(var i = 0; i < n; i++)
this.deleteCurrent( lSelected[0], lNext, lPrev, i !== lLast);
for (i = 0; i < n; i++) {
current = selected[i];
this.deleteCurrent(current);
}
}
return lSelected;
return selected;
};
/**
@ -1643,23 +1606,29 @@ var CloudCmd, Util, DOM, CloudFunc, Dialog;
*
* @pCurrent
*/
this.renameCurrent = function(pCurrentFile) {
if (!Cmd.isCurrentFile(pCurrentFile))
pCurrentFile = null;
this.renameCurrent = function(current) {
var from, to, dirPath, cmp, files;
var lCurrent = pCurrentFile || Cmd.getCurrentFile(),
lFrom = Cmd.getCurrentName(lCurrent),
lTo = Dialog.prompt('Rename', lFrom) || lFrom,
lDirPath = Cmd.getCurrentDirPath();
if (!Cmd.isCurrentFile(current))
current = Cmd.getCurrentFile();
if (!Util.strCmp(lFrom, lTo)) {
var lFiles = {
from : lDirPath + lFrom,
to : lDirPath + lTo
from = Cmd.getCurrentName(current),
to = Dialog.prompt('Rename', from) || from,
dirPath = Cmd.getCurrentDirPath();
cmp = Util.strCmp(from, to);
if (!cmp) {
files = {
from : dirPath + from,
to : dirPath + to
};
RESTful.mv(lFiles, function() {
DOM.setCurrentName(lTo, lCurrent);
RESTful.mv(files, function() {
var Storage = DOM.Storage,
path = CloudFunc.rmLastSlash(dirPath);
DOM.setCurrentName(to, current);
Storage.remove(path);
});
}
};
@ -1669,30 +1638,35 @@ var CloudCmd, Util, DOM, CloudFunc, Dialog;
*
* @pCurrent
*/
this.moveCurrent = function(pCurrentFile) {
if (!Cmd.isCurrentFile(pCurrentFile))
pCurrentFile = null;
this.moveCurrent = function(current) {
var name, from, to, cmp, files;
var lCurrent = pCurrentFile || Cmd.getCurrentFile(),
lName = Cmd.getCurrentName(lCurrent),
lFromPath = Cmd.getCurrentPath(),
lToPath = Cmd.getNotCurrentDirPath() + lName;
if (!Cmd.isCurrentFile(current))
current = Cmd.getCurrentFile();
lToPath = Dialog.prompt('Rename/Move file "' + lName + '"', lToPath);
name = Cmd.getCurrentName(current),
from = Cmd.getCurrentPath(),
to = Cmd.getNotCurrentDirPath() + name;
if (lToPath && !Util.strCmp(lFromPath, lToPath)) {
var lFiles = {
from : lFromPath,
to : lToPath
to = Dialog.prompt('Rename/Move file "' + name + '"', to);
cmp = !Util.strCmp(from, to);
if (to && cmp) {
files = {
from : from,
to : to
};
RESTful.mv(lFiles, function() {
DOM.deleteCurrent(lCurrent);
RESTful.mv(files, function() {
var dotDot,
panel = DOM.getPanel(true),
id = panel.id,
name = '..(' + id + ')';
var lPanel = DOM.getPanel(true),
lDotDot = DOM.getById( '..(' + lPanel.id + ')');
dotDot = DOM.getById(name);
DOM.setCurrentFile ( lDotDot );
DOM.deleteCurrent(current);
DOM.setCurrentFile (dotDot);
CloudCmd.refresh();
});
}
@ -1701,29 +1675,32 @@ var CloudCmd, Util, DOM, CloudFunc, Dialog;
/**
* copy current file
*
* @pCurrent
* @param current
*/
this.copyCurrent = function(pCurrentFile) {
if (!Cmd.isCurrentFile(pCurrentFile))
pCurrentFile = null;
this.copyCurrent = function(current) {
var name, from, to, files, cmp;
var lCurrent = pCurrentFile || Cmd.getCurrentFile(),
lName = Cmd.getCurrentName(lCurrent),
lFromPath = Cmd.getCurrentPath(),
lToPath = Cmd.getNotCurrentDirPath() + lName;
lToPath = Dialog.prompt( 'Copy file "' + lName + '" to', lToPath );
if (!Cmd.isCurrentFile(current))
current = Cmd.getCurrentFile();
if (lToPath && !Util.strCmp(lFromPath, lToPath)) {
var lFiles = {
from : lFromPath,
to : lToPath
name = Cmd.getCurrentName(current),
from = Cmd.getCurrentPath(),
to = Cmd.getNotCurrentDirPath() + name;
to = Dialog.prompt('Copy file "' + name + '" to', to);
cmp = Util.strCmp(from, to);
if (!cmp) {
files = {
from : from,
to : to
};
RESTful.cp(lFiles, function() {
var lPanel = DOM.getPanel(true),
lDotDot = DOM.getById( '..(' + lPanel.id + ')');
RESTful.cp(files, function() {
var panel = DOM.getPanel(true),
id = panel.id,
dotDot = DOM.getById( '..(' + id + ')');
DOM.setCurrentFile ( lDotDot );
DOM.setCurrentFile(dotDot);
CloudCmd.refresh();
});
}
@ -1814,8 +1791,7 @@ var CloudCmd, Util, DOM, CloudFunc, Dialog;
DOMTree = Util.extendProto(DOMTreeProto),
Events = Util.extendProto(EventsProto),
Images = Util.extendProto(ImagesProto),
RESTful = Util.extendProto(RESTfulProto),
Storage = Util.extendProto(StorageProto);
RESTful = Util.extendProto(RESTfulProto);
DOMProto = DOMFunc.prototype = new CmdProto();
@ -1826,7 +1802,6 @@ var CloudCmd, Util, DOM, CloudFunc, Dialog;
Events : Events,
RESTful : RESTful,
Images : Images,
Storage : Storage,
Dialog : Dialog
}
]);

View file

@ -139,6 +139,12 @@ var CloudCmd, Util, DOM, CloudFunc, ace, DiffProto, diff_match_patch;
exec : save
});
Ace.commands.addCommand({
name : 'saveMC',
bindKey : { win: 'F2', mac: 'F2' },
exec : save
});
ace.require('ace/ext/language_tools');
Modelist = ace.require('ace/ext/modelist');

View file

@ -21,6 +21,8 @@ var CloudCmd, Util, DOM;
INSERT : 45,
DELETE : 46,
ZERO : 48,
A : 65,
D : 68,
@ -87,7 +89,7 @@ var CloudCmd, Util, DOM;
ctrl = pEvent.ctrlKey;
/* если клавиши можно обрабатывать*/
if (Binded) {
if (!lAlt && !ctrl && lKeyCode >= KEY.A && lKeyCode <= KEY.Z)
if (!lAlt && !ctrl && lKeyCode >= KEY.ZERO && lKeyCode <= KEY.Z)
setCurrentByLetter(lKeyCode);
else {
Chars = [];

View file

@ -95,67 +95,9 @@ var Util, DOM, CloudCmd;
DOM.preventDefault(event);
},
/* right mouse click function varible */
onContextMenu = function(pEvent) {
var target,
isFunc = Util.isFunction(CloudCmd.Menu),
ret = true,
Key = CloudCmd.Key;
/* getting html element
* currentTarget - DOM event
* target - jquery event
*/
target = pEvent.currentTarget || pEvent.target;
DOM.setCurrentFile(target);
if (isFunc) {
CloudCmd.Menu({
x: pEvent.clientX,
y: pEvent.clientY
});
/* disabling browsers menu*/
ret = false;
}
return ret;
},
/* drag and drop function varible
* download file from browser to descktop
* in Chrome (HTML5)
*/
onDragStart = function(pEvent) {
var lElement = pEvent.target,
EXT = 'json',
isDir = Info.isDir,
lLink = lElement.href,
lName = lElement.textContent;
/* if it's directory - adding json extension */
if (isDir) {
lName += '.' + EXT;
lLink += '?' + EXT;
}
pEvent.dataTransfer.setData('DownloadURL',
'application/octet-stream' + ':' +
lName + ':' +
lLink);
},
setCurrentFile = function(pEvent) {
var pElement = pEvent.target,
lTag = pElement.tagName;
if (lTag !== 'LI')
do {
pElement = pElement.parentElement;
lTag = pElement.tagName;
} while(lTag !== 'LI');
DOM.setCurrentFile(pElement);
onTouchEnd = function(event) {
setCurrentFile(event);
loadDirOnce(event);
};
/* ставим загрузку гифа на клик*/
@ -195,7 +137,7 @@ var Util, DOM, CloudCmd;
else
events = {
'dblclick' : loadDirOnce,
'touchend' : loadDirOnce,
'touchend' : onTouchEnd,
'click' : DOM.preventDefault,
};
@ -209,6 +151,68 @@ var Util, DOM, CloudCmd;
}
};
function onContextMenu(event) {
var target,
isFunc = Util.isFunction(CloudCmd.Menu),
ret = true,
Key = CloudCmd.Key;
/* getting html element
* currentTarget - DOM event
* target - jquery event
*/
target = event.currentTarget || event.target;
DOM.setCurrentFile(target);
if (isFunc) {
CloudCmd.Menu({
x: event.clientX,
y: event.clientY
});
/* disabling browsers menu*/
ret = false;
}
return ret;
}
/*
* download file from browser to desktop
* in Chrome (HTML5)
*/
function onDragStart(event) {
var element = event.target,
EXT = 'json',
isDir = Info.isDir,
link = element.href,
name = element.textContent;
/* if it's directory - adding json extension */
if (isDir) {
name += '.' + EXT;
link += '?' + EXT;
}
event.dataTransfer.setData('DownloadURL',
'application/octet-stream' + ':' +
name + ':' +
link);
}
function setCurrentFile(event) {
var element = event.target,
tag = element.tagName;
if (tag !== 'LI')
do {
element = element.parentElement;
tag = element.tagName;
} while(tag !== 'LI');
DOM.setCurrentFile(element);
}
function appStorage() {
getConfig(function(config) {
var isAppStorage = config.appStorage,
@ -296,16 +300,17 @@ var Util, DOM, CloudCmd;
}
function pop() {
Events.add("popstate", function(pEvent) {
var lPath = pEvent.state + '?json';
Events.add("popstate", function(event) {
var path;
if (pEvent.state) {
lPath = pEvent.state + '?json';
CloudCmd.ajaxLoad(lPath, {nohistory: true});
} else
if (!event.state)
CloudCmd.route(location.hash);
return true;
else {
path = event.state + '?json';
CloudCmd.ajaxLoad(path, {
nohistory: true
});
}
});
}

View file

@ -17,6 +17,7 @@ var CloudCmd, Util, DOM, CloudFunc, $;
MenuSeted = false,
Menu = this,
Position,
Images = DOM.Images,
UploadToItemNames;
this.ENABLED = false;
@ -41,7 +42,7 @@ var CloudCmd, Util, DOM, CloudFunc, $;
if (!Loading) {
set();
DOM.Images.hideLoad();
Images.hideLoad();
if (Position && !Position.x )
Position = undefined;
@ -144,7 +145,7 @@ var CloudCmd, Util, DOM, CloudFunc, $;
* download menu item callback
*/
function downloadFromMenu(key, opt) {
DOM.Images.showLoad();
Images.showLoad();
var TIME = 1000,
lPath = Info.path,
@ -161,16 +162,16 @@ var CloudCmd, Util, DOM, CloudFunc, $;
async : false,
className : 'hidden',
src : lPath,
func : DOM.Images.hideLoad
func : Images.hideLoad
});
DOM.Images.hideLoad();
Images.hideLoad();
setTimeout(function() {
document.body.removeChild(lDownload);
}, TIME);
}
else
DOM.Images.showError({
Images.showError({
responseText: 'Error: You trying to' +
'download same file to often'});
}
@ -197,10 +198,14 @@ var CloudCmd, Util, DOM, CloudFunc, $;
lMenuItems.Download = downloadFromMenu;
lMenuItems.New = {
'File' : DOM.promptNewFile,
'Directory' : DOM.promptNewDir,
'File' : DOM.promptNewFile,
'Directory' : DOM.promptNewDir,
'From Cloud' : function() {
'From FilePicker' : function() {
Images.showLoad({
top: true
});
CloudCmd.execFromModule('FilePicker', 'saveFile', function(pName, pData) {
var lPath = DOM.getCurrentDirPath() + pName;

View file

@ -235,76 +235,4 @@ var Util, DOM, jQuery;
};
}
if (!window.localStorage) {
var Storage = function() {
/* приватный переключатель возможности работы с кэшем */
var StorageAllowed,
Data = {};
/* функция проверяет возможно ли работать с кэшем каким-либо образом */
this.isAllowed = function() {
return StorageAllowed;
};
this.setAllowed = function(pAllowed) {
StorageAllowed = pAllowed;
return pAllowed;
};
/** remove element */
this.remove = function(pItem) {
var lRet = this;
if (StorageAllowed)
delete Data[pItem];
return lRet;
};
/** если доступен localStorage и
* в нём есть нужная нам директория -
* записываем данные в него
*/
this.set = function(pName, pData) {
var lRet = this;
if (StorageAllowed && pName && pData)
Data[pName] = pData;
return lRet;
},
/** Если доступен Storage принимаем из него данные*/
this.get = function(pName) {
var lRet = false;
if (StorageAllowed)
lRet = Data[pName];
return lRet;
},
/* get all Storage from local storage */
this.getAll = function() {
var lRet = null;
if (StorageAllowed)
lRet = Data;
return lRet;
};
/** функция чистит весь кэш для всех каталогов*/
this.clear = function() {
var lRet = this;
if (StorageAllowed)
Data = {};
return lRet;
};
};
DOM.Storage = new Storage();
}
})(Util, DOM, jQuery);
})(Util, DOM, jQuery);

85
lib/client/storage.js Normal file
View file

@ -0,0 +1,85 @@
var Util, DOM;
(function(Util, DOM) {
'use strict';
var Storage = Util.extendProto(StorageProto),
DOMProto = Object.getPrototypeOf(DOM);
Util.extend(DOMProto, {
Storage: Storage
});
function StorageProto() {
/* приватный переключатель возможности работы с кэшем */
var Allowed;
/* функция проверяет возможно ли работать с кэшем каким-либо образом */
this.isAllowed = function() {
var ret = Allowed && !!window.localStorage;
return ret;
};
/**
* allow Storage usage
*/
this.setAllowed = function(isAllowed) {
Allowed = isAllowed;
};
/** remove element */
this.remove = function(item, callback) {
var ret = Allowed;
if (ret)
localStorage.removeItem(item);
Util.exec(callback, ret);
return this;
};
/** если доступен localStorage и
* в нём есть нужная нам директория -
* записываем данные в него
*/
this.set = function(name, data, callback) {
var str, ret = Allowed && name;
if (Util.isObject(data))
str = Util.stringifyJSON(data);
if (Allowed && name)
localStorage.setItem(name, str || data);
Util.exec(callback, ret);
return this;
},
/** Если доступен Storage принимаем из него данные*/
this.get = function(name, callback) {
var ret;
if (Allowed)
ret = localStorage.getItem(name);
Util.exec(callback, ret);
return this;
},
/** функция чистит весь кэш для всех каталогов*/
this.clear = function(callback) {
var ret = Allowed;
if (ret)
localStorage.clear();
Util.exec(callback, ret);
return this;
};
}
})(Util, DOM);

View file

@ -51,40 +51,42 @@ var CloudCmd, Util, DOM, CloudFunc, Github, cb;
}
GitHub.autorize = function(pCallBack, pCode) {
var lCode, lToken = Storage.get('token');
if (lToken) {
GitHub.Login(lToken);
Util.exec(pCallBack);
}
else {
lCode = pCode || window.location.search;
if (lCode || Util.isContainStr(lCode, '?code=') )
CloudCmd.getConfig(function(pConfig) {
DOM.ajax({
type : 'put',
url : pConfig && pConfig.apiURL + '/auth',
data : Util.removeStr(lCode, '?code='),
success : function(pData) {
if (pData && pData.token) {
lToken = pData.token;
GitHub.Login(lToken);
Storage.set('token', lToken);
Util.exec(pCallBack);
GitHub.autorize = function(callback, code) {
Storage.get('token', function(token) {
var code, isContain,
URL = '//' + window.location.host + '/auth/github';
if (token) {
GitHub.Login(token);
Util.exec(callback);
} else {
if (!code)
code = window.location.search;
isContain = Util.isContainStr(code, '?code=');
if (!isContain)
DOM.openWindow(URL);
else
CloudCmd.getConfig(function(config) {
DOM.ajax({
type : 'put',
url : config && config.apiURL + '/auth',
data : Util.removeStr(code, '?code='),
success : function(data) {
if (data && data.token) {
token = data.token;
GitHub.Login(token);
Storage.set('token', token);
Util.exec(callback);
} else
Util.log('Worning: token not getted...');
}
else
Util.log('Worning: token not getted...');
}
});
});
});
else{
var lUrl = '//' + window.location.host + '/auth/github';
DOM.openWindow(lUrl);
}
}
}
});
};
GitHub.getUserData = function(pCallBack) {

View file

@ -81,6 +81,7 @@ var CloudCmd, Util, DOM, CloudFunc, $;
$.fancybox(element, config);
} else {
Images.showLoad();
path = CloudFunc.FS + Info.path;
isImage = $.fancybox.isImage(path);

View file

@ -1,4 +1,4 @@
(function() {
(function() {
'use strict';
if (!global.cloudcmd)
@ -52,108 +52,120 @@
* @param pProcessing {index, appcache, rest}
*/
function start(options) {
var redirectServer,
config = main.config;
var redirectServer, port, ip, ssl, sslPort,
HTTP = 'http://',
HTTPS = 'https://',
config = main.config;
if (!options)
options = {};
Rest = options.rest;
Route = options.route;
Rest = options.rest;
Route = options.route;
init(options.appcache);
var lPort = process.env.PORT || /* c9 */
process.env.app_port || /* nodester */
process.env.VCAP_APP_PORT || /* cloudfoundry */
config.port,
lIP = process.env.IP || /* c9 */
config.ip ||
(main.WIN32 ? '127.0.0.1' : '0.0.0.0'),
lSSL = options.ssl,
lSSLPort = config.sslPort,
lHTTP = 'http://',
lHTTPS = 'https://',
lSockets = function(pServer) {
var listen, msg,
status = 'off';
if (config.socket && Socket) {
listen = Socket.listen(pServer);
if (listen) {
status = 'on';
Console.init();
Terminal.init();
}
}
msg = CloudFunc.formatMsg('sockets', '', status);
Util.log(msg);
},
lHTTPServer = function() {
expressApp = express.getApp([
Rest,
Route,
join,
controller
]);
Server = http.createServer(expressApp || respond);
Server.on('error', Util.log.bind(Util));
Server.listen(lPort, lIP);
lServerLog(lHTTP, lPort);
lSockets(Server);
},
lServerLog = function(http, port) {
Util.log('* Server running at ' + http + lIP + ':' + port);
};
port = process.env.PORT || /* c9 */
process.env.app_port || /* nodester */
process.env.VCAP_APP_PORT || /* cloudfoundry */
config.port,
ip = process.env.IP || /* c9 */
config.ip ||
(main.WIN32 ? '127.0.0.1' : '0.0.0.0'),
ssl = options.ssl,
sslPort = config.sslPort;
/* server mode or testing mode */
if (config.server)
if (lSSL) {
Util.log('* Redirection http -> https is setted up');
lServerLog(lHTTP, lPort);
if (!config.server)
Util.log('Cloud Commander testing mode');
else
if (!ssl)
createServer(port, ip, HTTP);
else {
createRedirect(port, ip, HTTPS, sslPort);
redirectServer = http.createServer(function(req, res) {
var url,
host = req.headers.host,
parsed = url.parse(host),
hostName = parsed.protocol;
url = lHTTPS + hostName + lSSLPort + req.url;
main.redirect({
response: res,
url: url
});
});
redirectServer.listen(lPort, lIP);
Server = https.createServer(lSSL, respond);
Server.on('error', function (error) {
Util.log('Could not use https port: ' + lSSLPort);
Util.log(error);
createServer(sslPort, ip, HTTP, ssl, function() {
Util.log('Could not use https port: ' + sslPort);
redirectServer.close();
Util.log('* Redirection http -> https removed');
lHTTPServer();
createServer(port, ip);
});
lSockets(Server);
Server.listen(lSSLPort, lIP);
lServerLog(lHTTPS, lSSLPort);
} else
lHTTPServer();
}
}
function createRedirect(port, ip, protocol, sslPort) {
var server = function(req, res) {
var url,
host = req.headers.host,
parsed = URL.parse(host),
hostName = parsed.protocol;
url = protocol + hostName + sslPort + req.url;
main.redirect({
response: res,
url: url
});
};
Util.log('* Redirection http -> https is setted up');
logServer(port, ip, protocol);
http.createServer(server)
.listen(port, ip);
}
function createServer(port, ip, protocol, ssl, callback) {
var server, app;
expressApp = express.getApp([
Rest,
Route,
join,
controller
]);
app = expressApp || respond;
if (ssl)
server = https.createServer(ssl, app);
else
Util.log('Cloud Commander testing mode');
server = http.createServer(app);
server.on('error', function(error) {
Util.log(error);
Util.exec(callback, error);
});
server.listen(port, ip);
logServer(port, ip, protocol);
addSockets(server);
}
function logServer(port, ip, http) {
Util.log('* Server running at ' + http + ip + ':' + port);
}
function addSockets(server) {
var listen, msg,
config = main.config,
status = 'off';
if (config.socket && Socket) {
listen = Socket.listen(server);
if (listen) {
status = 'on';
Console.init();
Terminal.init();
}
}
msg = CloudFunc.formatMsg('sockets', '', status);
Util.log(msg);
}
function respond(req, res) {

View file

@ -197,37 +197,40 @@
* query
* https://developers.google.com/speed/docs/best-practices/caching?hl=ru#LeverageProxyCaching
*/
function generateHeaders(pParams) {
var lRet = Util.checkObjTrue(pParams, ['name']);
function generateHeaders(params) {
var header, p, extension, type, encoding, isContain, cmp;
if (lRet) {
var p = pParams,
lExt = Util.getExtension(p.name),
lType = ext[lExt] || 'text/plain',
lContentEncoding = '';
if (params.name) {
p = params,
extension = Util.getExtension(p.name),
type = ext[extension] || 'text/plain',
encoding = '';
/* if type of file any, but img - then we shoud specify charset */
if (!Util.isContainStr(lType, 'img'))
lContentEncoding = '; charset=UTF-8';
isContain = Util.isContainStr(type, ['img', 'image']);
if (!isContain)
encoding = '; charset=UTF-8';
if (Util.isContainStr(p.query, 'download'))
lType = 'application/octet-stream';
isContain = Util.isContainStr(p.query, 'download');
if (isContain)
type = 'application/octet-stream';
lRet = {
header = {
'Access-Control-Allow-Origin' : '*',
'Content-Type' : lType + lContentEncoding,
'last-modified' : new Date().toString(),
'Content-Type' : type + encoding,
'last-modified' : '' + new Date(),
'Vary' : 'Accept-Encoding'
};
if (!Util.strCmp(lExt, '.appcache') && p.cache)
lRet['cache-control'] = 'max-age=' + 31337 * 21;
cmp = Util.strCmp(ext, '.appcache');
if (!cmp && p.cache)
header['cache-control'] = 'max-age=' + 31337 * 21;
if (p.gzip)
lRet['content-encoding'] = 'gzip';
header['content-encoding'] = 'gzip';
}
return lRet;
return header;
}
function mainSetHeader(pParams) {

View file

@ -103,115 +103,69 @@
p.command = Util.removeStrOneTime(p.name, '/');
switch(p.request.method) {
case 'GET':
ret = onGET(pParams);
break;
case 'PUT':
getBody(p.request, function(pBody) {
p.body = pBody;
onPUT(p);
});
break;
}
case 'GET':
ret = onGET(pParams);
break;
case 'PUT':
getBody(p.request, function(pBody) {
p.body = pBody;
onPUT(p);
});
break;
}
}
}
return ret;
}
function onFS(params) {
var p, lQuery, isGet,
var p, query, isGet,
ret = main.checkParams(params);
if (ret) {
p = params;
lQuery = main.getQuery(p.request);
query = main.getQuery(p.request);
p.name = Util.removeStrOneTime(p.name, CloudFunc.FS) || '/';
switch (p.request.method) {
case 'GET':
isGet = onFSGet(lQuery, p.name, function(error, result) {
checkSendError(error, params, function() {
sendResponse(p, result);
});
});
if (!isGet)
fs.stat(p.name, function(error, stat) {
var getDirContent = main.commander.getDirContent;
onFSGet(query, p.name, function(error, data, name, isFile) {
if (error)
sendError(params, error);
else if (isFile) {
p.name = name;
p.data = data;
if (error)
Util.exec(error);
else
if (!stat.isDirectory())
main.sendFile(p);
else
getDirContent(p.name, function(pError, pData) {
checkSendError(pError, p, function() {
p.name += '.json';
p.data = Util.stringifyJSON(pData);
sendResponse(p);
});
});
});
main.sendFile(p);
} else
sendResponse(p, data);
});
break;
case 'PUT':
if (lQuery === 'dir')
fse.mkdirs(p.name, function(pError) {
checkSendError(pError, params, function() {
sendMsg(params, 'make dir', p.name);
});
});
else if (lQuery === 'patch')
getBody(p.request, function(patch) {
fs.readFile(p.name, 'utf8', read.bind(null, p.name));
function read(name, error, data) {
checkSendError(error, p.params, function() {
var diffResult;
ret = Util.tryCatchLog(function() {
diffResult = diff.applyPatch(data, patch);
});
if (diffResult && !ret)
fs.writeFile(name, diffResult, write.bind(null, name));
else {
name = path.basename(name);
sendMsg(p.params, 'patch', name, 'fail');
}
});
}
function write(name, error) {
checkSendError(error, params, function() {
name = path.basename(name);
sendMsg(params, 'patch', name);
});
}
});
else
pipe.create({
read : p.request,
to : p.name,
callback : function(pError) {
checkSendError(pError, params, function() {
var lName = path.basename(p.name);
sendMsg(params, 'save', lName);
});
}
});
onFSPut(p.name, query, p.request, function(error, msg) {
if (error)
sendError(params, error);
else
sendResponse(params, msg);
});
break;
case 'DELETE':
onDelete(params, lQuery, function(error, msg, callback) {
checkSendError(error, params, function() {
if (callback)
Util.exec(callback);
else
sendMsg(params, 'delete', msg);
getBody(p.request, function(body) {
var files = Util.parseJSON(body);
onDelete(p.name, files, query, function(error, callback) {
checkSendError(error, params, function() {
var names = files.length ? files : p.name;
if (callback)
Util.exec(callback);
else
sendMsg(params, 'delete', names);
});
});
});
break;
@ -221,57 +175,123 @@
return ret;
}
function onDelete(params, query, callback) {
var rmFile = fs.unlink.bind(fs),
rmDir = fse.remove.bind(fse),
p = params;
function onFSPut(name, query, readStream, callback) {
var func = Util.retExec(callback),
baseName = path.basename(name);
if (query === 'dir')
rmDir(p.name, function(error) {
Util.exec(callback, error, p.name);
});
else if (query === 'files')
getBody(p.request, function(body) {
var i, name,
files = Util.parseJSON(body),
n = files.length,
dir = p.name,
log = Util.log.bind(Util),
assync = 0;
switch(query) {
case 'dir':
fse.mkdirs(name, function(error) {
var msg;
function onStat(name, error, stat) {
++assync;
if (!error)
msg = CloudFunc.formatMsg('make dir', name);
func(error, msg);
});
break;
default:
pipe.create({
read : readStream,
to : name,
callback : function(error) {
var msg;
if (!error)
msg = CloudFunc.formatMsg('save', baseName);
func(error, msg);
}
});
break;
case 'patch':
getBody(readStream, function(patch) {
fs.readFile(name, 'utf8', read);
function read(error, data) {
var diffResult;
if (error)
Util.exec(callback, error);
func(error);
else {
if (stat.isDirectory())
rmDir(name, log);
error = Util.tryCatchLog(function() {
diffResult = diff.applyPatch(data, patch);
});
else if (stat.isFile())
rmFile(name, log);
if (assync === n)
Util.exec(callback, null, body);
if (diffResult && !error)
fs.writeFile(name, diffResult, write);
else {
msg = CloudFunc.formatMsg('patch', baseName, 'fail');
func(null, msg);
}
}
}
for (i = 0; i < n; i ++) {
name = dir + files[i];
function write(name, error) {
var msg;
Util.log(name);
if (!error)
msg = CloudFunc.formatMsg('patch', baseName);
fs.stat(name, onStat.bind(null, name));
func(error, msg);
}
});
else
rmFile(p.name, function(error) {
Util.exec(callback, error, p.name);
});
break;
}
}
function onDelete(name, files, query, callback) {
var i, n, onStat,
assync = 0,
rmFile = fs.unlink.bind(fs),
rmDir = fse.remove.bind(fse),
func = Util.retExec(callback);
switch(query) {
default:
rmFile(name, func);
break;
case 'dir':
rmDir(name, func);
break;
case 'files':
n = files && files.length,
dir = name;
onStat = function(name, error, stat) {
var log = Util.log.bind(Util);
++assync;
if (error)
func(error);
else {
if (stat.isDirectory())
rmDir(name, log);
else if (stat.isFile())
rmFile(name, log);
if (assync === n)
func();
}
};
for (i = 0; i < n; i ++) {
name = dir + files[i];
Util.log(name);
fs.stat(name, onStat.bind(null, name));
}
break;
}
}
function onFSGet(query, name, callback) {
var msg, hash, ret = true;
var error, hash,
func = Util.retExec(callback);
switch (query) {
case 'size':
@ -279,14 +299,18 @@
if (!error)
size = CloudFunc.getShortSize(size);
Util.exec(callback, error, size);
func(error, size);
});
break;
case 'time':
time.get(name, function(error, time) {
var timeStr = time.toString();
Util.exec(callback, error, timeStr);
var timeStr;
if (!error)
timeStr = time.toString();
func(error, timeStr);
});
break;
@ -294,26 +318,46 @@
hash = Hash.create();
if (!hash) {
msg = 'not suported, try update node';
msg = CloudFunc.formatMsg('hash', msg, 'error');
Util.exec(callback, msg);
error = 'not suported, try update node';
error = CloudFunc.formatMsg('hash', error, 'error');
func(error);
} else
pipe.create({
from : name,
write : hash,
callback : function (error) {
var hex = hash.get();
Util.exec(callback, error, hex);
var hex;
if (!error)
hash = hash.get();
func(error, hash);
}
});
break;
default:
ret = false;
fs.stat(name, function(error, stat) {
var getDirContent = main.commander.getDirContent,
isFile = !stat.isDirectory();
if (error)
func(error);
else
if (isFile)
func(null, null, null, isFile);
else
getDirContent(name, function(error, data) {
if (!error) {
name += '.json';
data = Util.stringifyJSON(data);
}
func(error, name, data);
});
});
break;
}
return ret;
}
/**
@ -454,18 +498,18 @@
/**
* get body of url query
*
* @param pReq
* @param pCallBack
* @param req
* @param callback
*/
function getBody(req, pCallBack) {
var lBody = '';
function getBody(req, callback) {
var body = '';
req.on('data', function(chunk) {
lBody += chunk.toString();
body += chunk.toString();
});
req.on('end', function() {
Util.exec(pCallBack, lBody);
Util.exec(callback, body);
});
}

View file

@ -565,42 +565,43 @@
/**
* function render template with view
* @pTempl
* @pView
* @templ
* @view
*/
this.render = function(pTempl, pView) {
var lRet = Util.ownRender(pTempl, pView);
this.render = function(templ, view) {
var ret,
NOT_ESCAPE = true,
SPACES = '\\s*',
symbols = ['{{' + SPACES, SPACES + '}}'];
ret = Util.ownRender(templ, view, symbols, NOT_ESCAPE);
return lRet;
return ret;
};
/**
* function render template with view and own symbols
* @pTempl
* @pView
* @pSymbols
* @templ
* @view
* @symbols
*/
this.ownRender = function(pTempl, pView, pSymbols) {
var SPACES = '\\s*';
if (!pSymbols)
pSymbols = ['{{' + SPACES, SPACES + '}}'];
var lRet = pTempl,
lFirstChar,
lSecondChar;
this.ownRender = function(templ, view, symbols, notEscape) {
var str, param, expr,
ret = templ,
firstChar,
secondChar;
lFirstChar = pSymbols[0];
lSecondChar = pSymbols[1] || lFirstChar;
firstChar = symbols[0];
secondChar = symbols[1] || firstChar;
for(var lVar in pView) {
var lStr = pView[lVar];
lStr = Util.exec(lStr) || lStr;
lRet = Util.replaceStr(lRet, lFirstChar + lVar + lSecondChar, lStr, true);
for (param in view) {
str = view[param];
str = Util.exec(str) || str;
expr = firstChar + param + secondChar;
ret = Util.replaceStr(ret, expr, str, notEscape);
}
return lRet;
return ret;
};
@ -853,7 +854,7 @@
args = Util.slice(arguments, 1);
if (Util.isFunction(callback))
ret = callback.apply(null, args);
ret = callback.apply(null, args);
return ret;
};

View file

@ -1,6 +1,6 @@
{
"name": "cloudcmd",
"version": "0.8.1",
"version": "0.8.2",
"author": "coderaiser <mnemonic.enemy@gmail.com> (https://github.com/coderaiser)",
"description": "Cloud Commander - file manager with console and editor",
"homepage": "http://cloudcmd.io",
@ -18,7 +18,7 @@
"subdomain": "cloudcmd",
"dependencies": {
"dropbox": "0.10.2",
"minify": "0.2.5",
"minify": "0.2.6",
"socket.io": "0.9.16",
"express": "3.4.x",
"http-auth": "2.1.x",

View file

@ -1,8 +1,14 @@
#!/bin/sh
if test -z $1
then
echo "log.sh <tag>"
echo 'log.sh <tag>'
else
git log $1..HEAD --pretty=format:"- %s" --grep fix
git log $1..HEAD --pretty=format:"- %s" --grep feature
echo 'fix:'
git log $1..HEAD --pretty=format:"- %s" --grep fix | sed 's/fix//g'
echo '\n'
echo 'feature:'
git log $1..HEAD --pretty=format:"- %s" --grep feature | sed 's/feature//g'
echo '\n\n'
fi

View file

@ -34,7 +34,7 @@
Expect =
'<div id="js-path" class="reduce-text" title="/etc/X11/">' +
'<div data="js-path" class="reduce-text" title="/etc/X11/">' +
'<span class="path-icon clear-storage" ' +
'title="clear storage (Ctrl+D)">' +
'</span>' +