From 772e017ca222dbcc5d4843b0e685b897cf5f83e8 Mon Sep 17 00:00:00 2001 From: node Date: Tue, 3 Jul 2012 07:55:59 +0000 Subject: [PATCH 01/32] Initial commit via nodester-cli --- .gitignore | 1 + package.json | 5 +++++ server.js | 5 +++++ 3 files changed, 11 insertions(+) create mode 100644 .gitignore create mode 100644 package.json create mode 100644 server.js diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..029a5e87 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.nodester.appconfig diff --git a/package.json b/package.json new file mode 100644 index 00000000..9881303b --- /dev/null +++ b/package.json @@ -0,0 +1,5 @@ +{ + "name":"cloudcmd", + "node":"0.6.17", + "author":"coderaiser" +} \ No newline at end of file diff --git a/server.js b/server.js new file mode 100644 index 00000000..97b1d1af --- /dev/null +++ b/server.js @@ -0,0 +1,5 @@ +var http = require('http'); +http.createServer(function (req, res) { + res.writeHead(200, {'Content-Type': 'text/plain'}); + res.end('Hello World\nApp (cloudcmd) is running on Node.JS ' + process.version); +}).listen(process.env['app_port'] || 3000); From e450ea64587cfa8ef9f83b4aa6bec060fb62ae00 Mon Sep 17 00:00:00 2001 From: node Date: Tue, 3 Jul 2012 08:26:30 +0000 Subject: [PATCH 02/32] first commit --- package.json | 8 +- server.js | 642 ++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 642 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index 9881303b..738a4580 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,7 @@ { - "name":"cloudcmd", - "node":"0.6.17", - "author":"coderaiser" + "name": "cloudcmd", + "version": "0.0.1-5", + "scripts":{"test":"sh test/test.sh","start": "server.js"}, + "engines": { "node": "0.6.x" }, + "subdomain": "cloudcmd" } \ No newline at end of file diff --git a/server.js b/server.js index 97b1d1af..200b7cb7 100644 --- a/server.js +++ b/server.js @@ -1,5 +1,637 @@ -var http = require('http'); -http.createServer(function (req, res) { - res.writeHead(200, {'Content-Type': 'text/plain'}); - res.end('Hello World\nApp (cloudcmd) is running on Node.JS ' + process.version); -}).listen(process.env['app_port'] || 3000); +"use strict"; + +/* Обьект содержащий все функции и переменные + * серверной части Cloud Commander'а + */ +var CloudServer={ + /* функция, которая генерирует заголовки + * файлов, отправляемые сервером клиенту + */ + generateHeaders :function(){}, + /* функция высылает + * данные клиенту + */ + sendResponse :function(){}, + /* Структура содержащая функции, + * и переменные, в которых + * говориться о поддерживаемых + * браузером технологиях + */ + BrowserSuport :{}, + /* Обьект для работы с кэшем */ + Cashe :{}, + /* Обьект через который + * выполняеться сжатие + * скриптов и стилей + */ + Minify :{}, + /* Асоциативный масив обьектов для + * работы с ответами сервера + * высылаемыми на запрос о файле и + * хранащий информацию в виде + * Responces[name]=responce; + */ + Responses :{}, + + /* ПЕРЕМЕННЫЕ */ + /* Поддержка браузером JS*/ + NoJS :true, + /* Поддержка gzip-сжатия + * браузером + */ + Gzip :undefined, + + /* КОНСТАНТЫ */ + /* index.html */ + INDEX :'index.html', + /* name of direcotory with libs */ + LIBDIR :'./lib', + LIBDIRSERVER :'./lib/server', +}; + +/* + * Обьект для работы с кэшем + * аналог клиентского обьекта + * с тем отличием, что в нём + * будут храниться серверные + * данные, такие как файлы + * отдаваемые клиенту + * (файлы проэкта по большому + * счёту, для ускорения + * первичной загрузки) + */ +CloudServer.Cache={ + _allowed :true, /* приватный переключатель возможности работы с кэшем */ + /* данные в которых храняться файлы + * в формате <поле> : <значение> + * _data[name]=pData; + * одному имени соответствуют + * одни данные + */ + _data :{}, + + /* функция говорит можно ли работать с кэшем */ + isAllowed :(function(){ + return CloudServer.Cache._allowed; + }), + /* функция устанавливает возможность работать с кэшем */ + setAllowed :(function(pAllowed){ + CloudServer.Cache._allowed=pAllowed; + }), + /* Если доступен кэш + * сохраняем в него данные + */ + set :(function(pName, pData){ + if(CloudServer.Cache._allowed && pName && pData){ + CloudServer.Cache._data[pName]=pData; + } + }), + /* Если доступен Cache принимаем из него данные*/ + get :(function(pName){ + if(CloudServer.Cache._allowed && pName){ + return CloudServer.Cache._data[pName]; + } + else return null; + }), + + /* Функция очищает кэш*/ + clear :(function(){ + if(CloudServer.Cache._allowed){ + CloudServer.Cache._data={}; + } + }) +}; + +/* Обьект для сжатия скриптов и стилей + * по умолчанию - сжимаються + */ +CloudServer.Minify={ + /* приватный переключатель минимизации */ + _allowed :{css:true,js:true,html:true, img: true}, + + /* функция разрешает или + * запрещает минимизировать + * css/js/html + * @pAllowed: - структура, в которой + * передаються параметры + * минификации, вида + * {js:true,css:true,html:false; img:true} + * img отвечает за перевод картинок в base64 + * и сохранение их в css-файл + */ + setAllowed :(function(pAllowed){ + if(pAllowed){ + this._allowed.css=pAllowed.css; + this._allowed.js=pAllowed.js; + this._allowed.html=pAllowed.html; + this._allowed.img=pAllowed.img; + } + }), + + /* + * Функция минимизирует css/js/html + * если установлены параметры минимизации + */ + doit :(function(){ + if(this._allowed.css || + this._allowed.js || + this._allowed.html){ + var lMinify = require(CloudServer.LIBDIRSERVER+'/minify'); + + this.done.js=this._allowed.js?lMinify.jsScripts():false; + this.done.html=this._allowed.html?lMinify.html():false; + this.done.css=this._allowed.css?lMinify.cssStyles(this._allowed.img):false; + } + }), + /* свойство показывающее случилась ли ошибка*/ + done:{js: false,css: false, html:false} +}; + + +var LeftDir='/'; +var RightDir=LeftDir; +/* + var Path = require('path'); +*/ /* модуль для работы с путями*/ + +var Fs = require('fs'); /* модуль для работы с файловой системой*/ + +var Zlib; +/* node v0.4 not contains zlib + */ +try{ + Zlib = require('zlib'); /* модуль для сжатия данных gzip-ом*/ +}catch(error){ + Zlib=undefined; + console.log('to use gzip-commpression' + + 'you should install zlib module\n' + + 'npm install zlib'); +} +var CloudFunc = require(CloudServer.LIBDIR + + (CloudServer.Minify.done.js?/* если стоит минификация*/ + '/cloudfunc.min':/* добавляем сжатый - иначе обычный */ + '/cloudfunc')); /* модуль с функциями */ +/* конструктор*/ +CloudServer.init=(function(){ + /* Переменная в которой храниться кэш*/ + CloudServer.Cache.setAllowed(true); + /* Change default parameters of + * js/css/html minification + */ + CloudServer.Minify.setAllowed({ + js:true, + css:true, + html:true, + img:true + }); + /* Если нужно минимизируем скрипты */ + CloudServer.Minify.doit(); +}); + + +/* создаём сервер на порту 31337*/ +CloudServer.start=function() +{ + CloudServer.init(); + + var http = require('http'); + http.createServer(CloudServer._controller).listen(process.env.PORT || + process.env.VCAP_APP_PORT /* cloudfoundry */ || + 19271, + '0.0.0.0' || '127.0.0.1'); + console.log('Cloud Commander server running at http://127.0.0.1:'+ + (process.env.PORT===undefined?19271:process.env.PORT)); +}; + + +/* Функция создаёт заголовки файлов + * в зависимости от расширения файла + * перед отправкой их клиенту + * @pName - имя файла + * @pGzip - данные сжаты gzip'ом + */ +CloudServer.generateHeaders = function(pName, pGzip){ + var lType=''; + /* высылаем заголовок в зависимости от типа файла */ + /* если расширение у файла css - + * загружаем стили + */ + if(CloudFunc.checkExtension(pName,'css')) + lType='text/css'; + /* загружаем js */ + else if(CloudFunc.checkExtension(pName,'js')) + lType='text/javascript'; + /* загружаем картинки*/ + else if(CloudFunc.checkExtension(pName,'png')) + lType='image/png'; + /* загружаем json*/ + else if(CloudFunc.checkExtension(pName,'json')) + lType='application/json'; + else if(CloudFunc.checkExtension(pName,'html')) + lType='text/html'; + else if(CloudFunc.checkExtension(pName,'appcache')) + lType='text/cache-manifest'; + /* если это неизвестный тип файла - + * высылаем его просто как текст + */ + else lType='text/plain'; + + return { + /* if type of file any, but img - + * then we shoud specify charset + */ + 'Content-Type': lType + (lType.indexOf('img')<0?'; charset=UTF-8':''), + 'cache-control': 'max-age='+(31337*21), + 'last-modified': new Date().toString(), + 'content-encoding': pGzip?'gzip':'', + /* https://developers.google.com/speed/docs/best-practices/caching?hl=ru#LeverageProxyCaching */ + 'Vary': 'Accept-Encoding' + }; +}; + +/* + * Главная функция, через которую проихсодит + * взаимодействие, обмен данными с клиентом + * @req - запрос клиента (Request) + * @res - ответ сервера (Response) + */ +CloudServer._controller=function(pReq, pRes) +{ + /* Читаем содержимое папки, + переданное в url + */ + var url = require("url"); + var pathname = url.parse(pReq.url).pathname; + console.log('pathname: '+pathname); + + /* получаем поддерживаемые браузером кодировки*/ + var lAcceptEncoding = pReq.headers['accept-encoding']; + /* запоминаем поддерживает ли браузер + * gzip-сжатие при каждом обращении к серверу + * и доступен ли нам модуль zlib + */ + if (lAcceptEncoding && + lAcceptEncoding.match(/\bgzip\b/) && + Zlib){ + CloudServer.Gzip=true; + }else + CloudServer.Gzip=false; + /* путь в ссылке, который говорит + * что js отключен + */ + var lNoJS_s=CloudFunc.NOJS; + var lFS_s=CloudFunc.FS; + + if(pathname!=='/favicon.ico') + { + console.log("request for " + pathname + " received..."); + var lName; + + /* если в пути нет информации ни о ФС, + * ни об отсутствии js, + * ни о том, что это корневой + * каталог - загружаем файлы проэкта + */ + if(pathname.indexOf(lFS_s)<0 && + pathname.indexOf(lNoJS_s)<0 && + pathname!=='/'){ + /* если имена файлов проекта - загружаем их*/ + /* убираем слеш и читаем файл с текущец директории*/ + //lName=Path.basename(pathname); + + /* добавляем текующий каталог к пути */ + lName='.'+pathname; + console.log('reading '+lName); + /* сохраняем указатель на responce и имя */ + CloudServer.Responses[lName]=pRes; + + /* Берём значение из кэша + * сжатый файл - если gzip-поддерживаеться браузером + * не сжатый - в обратном случае + */ + var lFileData=CloudServer.Cache.get(CloudServer.Gzip?(lName+'_gzip'):lName); + + var lReadFileFunc_f=CloudServer.getReadFileFunc(lName); + /* если там что-то есть передаём данные в функцию + * readFile + */ + if(lFileData){ + console.log('readed from cache'); + /* передаём данные с кэша, + * если gzip включен - сжатые + * в обратном случае - несжатые + */ + lReadFileFunc_f(undefined,lFileData,true); + } + else Fs.readFile(lName,lReadFileFunc_f); + + }else{/* если мы имеем дело с файловой системой*/ + /* если путь не начинаеться с no-js - значит + * js включен + */ + /* убираем пометку cloud, без которой c9.io + * не работает поскольку путь из двух слешей + * (/fs/no-js/) - очень короткий, нужно + * длиннее + */ + + if(pathname.indexOf(lNoJS_s)!==lFS_s.length && pathname!=='/'){ + CloudServer.NoJS=false; + }else pathname=pathname.replace(lNoJS_s,''); + + /* убираем индекс файловой системы */ + if(pathname.indexOf(lFS_s)===0){ + pathname=pathname.replace(lFS_s,''); + /* если посетитель только зашел на сайт + * no-js будет пустым, как и fs + */ + /* если в пути нету fs - посетитель только зашел на сайт + * загружаем его полностью. + */ + }else CloudServer.NoJS=true; + /* если в итоге путь пустой + * делаем его корневым + */ + if(pathname==='')pathname='/'; + + RightDir=pathname; + LeftDir=pathname; + + /* если встретиться пробел - + * меня код символа пробела на пробел + */ + + LeftDir=CloudFunc.replaceSpaces(LeftDir); + RightDir=CloudFunc.replaceSpaces(RightDir); + + /* Проверяем с папкой ли мы имеем дело */ + + /* читаем сновные данные о файле */ + var lStat; + try{ + lStat=Fs.statSync(LeftDir); + }catch(error){ + console.log(error); + CloudServer.Responses[LeftDir]=pRes; + CloudServer.sendResponse('OK',error.toString(),LeftDir); + } + /* если это каталог - + * читаем его содержимое + */ + try{ + /* если установлено сжатие + * меняем название html-файла и + * загружаем сжатый html-файл в дальнейшем + */ + CloudServer.INDEX=(CloudServer.Minify.done.html?'index.min.html':CloudServer.INDEX); + /* + * сохраним указатель на response + */ + CloudServer.Responses[CloudServer.INDEX]=pRes; + if(lStat.isDirectory()) + Fs.readdir(LeftDir,CloudServer._readDir); + /* отдаём файл */ + else if(lStat.isFile()){ + CloudServer.Responses[LeftDir]=pRes; + Fs.readFile(LeftDir,CloudServer.getReadFileFunc(LeftDir)); + console.log('reading file: '+LeftDir); + } + }catch(error){console.log(error);} + } + } +}; + +/* Функция читает ссылку или выводит информацию об ошибке*/ +CloudServer._readDir=function (pError, pFiles) +{ + if(!pError) + { + /* данные о файлах в формате JSON*/ + var lJSON=[]; + var lJSONFile={}; + /* Если мы не в корне добавляем слеш к будующим ссылкам */ + if(LeftDir!=='/') + { + RightDir+='/'; + LeftDir+='/'; + } + + pFiles=pFiles.sort(); + + lJSON[0]={path:LeftDir,size:'dir'}; + var fReturnFalse=function returnFalse(){return false;}; + for(var i=0;i','') + .replace('style.css','all.min.css') + :lIndex; + + lIndex = CloudServer.Minify.done.js?lIndex.replace('client.js','client.min.js'):lIndex; + + lIndex=lIndex.toString().replace('
','
'+lList); + /* меняем title */ + lIndex=lIndex.replace('Cloud Commander', + ''+CloudFunc.setTitle()+''); + /* отображаем панель быстрых клавишь */ + lList=lIndex; + /* если браузер поддерживает gzip-сжатие*/ + lHeader=CloudServer.generateHeaders('text/html',CloudServer.Gzip); + }catch(error){console.log(error);} + }else{ + /* в обычном режиме(когда js включен + * высылаем json-структуру файлов + * с соответствующими заголовками + */ + lList=JSON.stringify(lJSON); + lHeader=CloudServer.generateHeaders('application/json',CloudServer.Gzip); + } + /* если браузер поддерживает gzip-сжатие - сжимаем данные*/ + if(CloudServer.Gzip){ + Zlib.gzip(lList,CloudServer.getGzipDataFunc(lHeader,CloudServer.INDEX)); + } + /* если не поддерживаеться - отсылаем данные без сжатия*/ + else + CloudServer.sendResponse(lHeader,lList,CloudServer.INDEX); + } + else + { + console.log(pError); + CloudServer.sendResponse('OK',pError.toString()); + } +}; + +/* Функция генерирует функция считывания файла + * таким образом, что бы у нас было + * имя считываемого файла + * @pName - полное имя файла + */ +CloudServer.getReadFileFunc = function(pName){ +/* + * @pError - ошибка + * @pData - данные + * @pFromFile - прочитано с файла bool + */ + var lReadFile=function(pError,pData,pFromCache_b){ + if (!pError){ + console.log('file ' + pName + ' readed'); + + /* берём из кэша данные файла + * если их нет в кэше - + * сохраняем + */ + if(!pFromCache_b && CloudServer.Cache.isAllowed) + CloudServer.Cache.set(pName,pData); + /* если кэш есть + * сохраняем его в переменную + * которая до этого будет пустая + * по скольку мы будем вызывать этот метод + * сами, ведь файл уже вычитан + */ + + var lHeader=CloudServer.generateHeaders(pName,CloudServer.Gzip); + /* если браузер поддерживает gzip-сжатие - сжимаем данные*/ + if(CloudServer.Gzip &&!pFromCache_b){ + /* сжимаем содержимое */ + Zlib.gzip(pData,CloudServer.getGzipDataFunc(lHeader,pName)); + } + else{ + /* высылаем несжатые данные */ + CloudServer.sendResponse(lHeader,pData,pName); + } + } + else + { + console.log(pError.path); + if(pError.path!=='passwd.json') + { + console.log(pError); + CloudServer.sendResponse('OK',pError.toString()); + }else{ + CloudServer.sendResponse('OK','passwd.json'); + } + } + }; + return lReadFile; +}; + +/* Функция получает сжатые данные + * @pHeader - заголовок файла + */ +CloudServer.getGzipDataFunc=function(pHeader,pName){ + return function(error,pResult){ + if(!error){ + /* отправляем сжатые данные + * вместе с заголовком + */ + /* если установлена работа с кэшем + * сохраняем сжатые данные + */ + if(CloudServer.Cache.isAllowed){ + /* устанавливаем кєш */ + console.log(pName+' gziped'); + CloudServer.Cache.set(pName+'_gzip',pResult); + } + CloudServer.sendResponse(pHeader,pResult,pName); + } + else{ + console.log(error); + CloudServer.sendResponse(pHeader,error); + } + }; +}; +/* Функция высылает ответ серверу + * @pHead - заголовок + * @pData - данные + * @pName - имя отсылаемого файла + */ +CloudServer.sendResponse = function(pHead, pData,pName){ + /* если у нас есть указатель на responce + * для соответствующего файла - + * высылаем его + */ + var lResponse=CloudServer.Responses[pName]; + if(lResponse){ + lResponse.writeHead(200,pHead); + lResponse.end(pData); + console.log(pName+' sended'); + } +}; + +CloudServer.start(); From 311ff3b9d6a2aed3cc5e6f27b6529ab8c0bbf03d Mon Sep 17 00:00:00 2001 From: node Date: Tue, 3 Jul 2012 08:30:21 +0000 Subject: [PATCH 03/32] all added --- README.md | 50 ++ client.js | 716 ++++++++++++++++++++++++++ cloudcmd | 1 + cloudcmd1/1/README.md | 49 ++ cloudcmd1/1/client.js | 736 +++++++++++++++++++++++++++ cloudcmd1/1/index.html | 54 ++ cloudcmd1/1/package.json | 11 + cloudcmd1/1/package2.json | 12 + cloudcmd1/1/reset.css | 100 ++++ cloudcmd1/1/server.js | 635 +++++++++++++++++++++++ cloudcmd1/1/style.css | 317 ++++++++++++ cloudcmd1/1/test.sh | 4 + cloudcmd1/README.md | 49 ++ cloudcmd1/client.js | 736 +++++++++++++++++++++++++++ cloudcmd1/img/console_clear.png | Bin 0 -> 1344 bytes cloudcmd1/img/dir.png | Bin 0 -> 537 bytes cloudcmd1/img/panel_refresh.png | Bin 0 -> 872 bytes cloudcmd1/img/spinner.gif | Bin 0 -> 1569 bytes cloudcmd1/img/txt.png | Bin 0 -> 294 bytes cloudcmd1/index.html | 54 ++ cloudcmd1/lib/README.md | 5 + cloudcmd1/lib/client/keyBinding.js | 248 +++++++++ cloudcmd1/lib/cloudfunc.js | 513 +++++++++++++++++++ cloudcmd1/lib/server/minify.js | 274 ++++++++++ cloudcmd1/node_modules/.bin/jitsu | 1 + cloudcmd1/node_modules/.bin/nodester | 1 + cloudcmd1/node_modules/jitsu | 1 + cloudcmd1/node_modules/nodester-cli | 1 + cloudcmd1/package.json | 16 + cloudcmd1/package2.json | 12 + cloudcmd1/reset.css | 100 ++++ cloudcmd1/server.js | 635 +++++++++++++++++++++++ cloudcmd1/style.css | 317 ++++++++++++ cloudcmd1/test.sh | 4 + css/reset.css | 90 ++++ css/style.css | 317 ++++++++++++ img/console_clear.png | Bin 0 -> 1344 bytes img/dir.png | Bin 0 -> 537 bytes img/panel_refresh.png | Bin 0 -> 872 bytes img/spinner.gif | Bin 0 -> 1569 bytes img/txt.png | Bin 0 -> 294 bytes index.html | 54 ++ lib/README.md | 5 + lib/client/keyBinding.js | 248 +++++++++ lib/cloudfunc.js | 504 ++++++++++++++++++ lib/server/minify.js | 276 ++++++++++ node_modules/.bin/jitsu | 1 + node_modules/.bin/nodester | 1 + node_modules/jitsu | 1 + node_modules/nodester-cli | 1 + package2.json | 12 + package_was.json | 11 + test/test.sh | 6 + 53 files changed, 7179 insertions(+) create mode 100644 README.md create mode 100644 client.js create mode 160000 cloudcmd create mode 100644 cloudcmd1/1/README.md create mode 100644 cloudcmd1/1/client.js create mode 100644 cloudcmd1/1/index.html create mode 100644 cloudcmd1/1/package.json create mode 100644 cloudcmd1/1/package2.json create mode 100644 cloudcmd1/1/reset.css create mode 100644 cloudcmd1/1/server.js create mode 100644 cloudcmd1/1/style.css create mode 100644 cloudcmd1/1/test.sh create mode 100644 cloudcmd1/README.md create mode 100644 cloudcmd1/client.js create mode 100644 cloudcmd1/img/console_clear.png create mode 100644 cloudcmd1/img/dir.png create mode 100644 cloudcmd1/img/panel_refresh.png create mode 100644 cloudcmd1/img/spinner.gif create mode 100644 cloudcmd1/img/txt.png create mode 100644 cloudcmd1/index.html create mode 100644 cloudcmd1/lib/README.md create mode 100644 cloudcmd1/lib/client/keyBinding.js create mode 100644 cloudcmd1/lib/cloudfunc.js create mode 100644 cloudcmd1/lib/server/minify.js create mode 120000 cloudcmd1/node_modules/.bin/jitsu create mode 120000 cloudcmd1/node_modules/.bin/nodester create mode 120000 cloudcmd1/node_modules/jitsu create mode 120000 cloudcmd1/node_modules/nodester-cli create mode 100644 cloudcmd1/package.json create mode 100644 cloudcmd1/package2.json create mode 100644 cloudcmd1/reset.css create mode 100644 cloudcmd1/server.js create mode 100644 cloudcmd1/style.css create mode 100644 cloudcmd1/test.sh create mode 100644 css/reset.css create mode 100644 css/style.css create mode 100644 img/console_clear.png create mode 100644 img/dir.png create mode 100644 img/panel_refresh.png create mode 100644 img/spinner.gif create mode 100644 img/txt.png create mode 100644 index.html create mode 100644 lib/README.md create mode 100644 lib/client/keyBinding.js create mode 100644 lib/cloudfunc.js create mode 100644 lib/server/minify.js create mode 120000 node_modules/.bin/jitsu create mode 120000 node_modules/.bin/nodester create mode 120000 node_modules/jitsu create mode 120000 node_modules/nodester-cli create mode 100644 package2.json create mode 100644 package_was.json create mode 100644 test/test.sh diff --git a/README.md b/README.md new file mode 100644 index 00000000..62e574e6 --- /dev/null +++ b/README.md @@ -0,0 +1,50 @@ +Cloud Commander [![Build Status](https://secure.travis-ci.org/coderaiser/cloudcmd.png?branch=master)](http://travis-ci.org/coderaiser/cloudcmd) +=============== +**Cloud Commander** - two-panels file manager, totally writed on js. +View [demo](http://demo-cloudcmd.cloudfoundry.com/ "demo"). + +Google PageSpeed Score : [100](https://developers.google.com/speed/pagespeed/insights#url=http_3A_2F_2Fdemo-cloudcmd.cloudfoundry.com_2F&mobile=false "score") (out of 100). + +Benefits +--------------- +- full browser compatibility *(ie6+,chrome,safari,opera,firefox)*; +- responsible design +- one full page loading, *and then just one-time json-dir-listings loading +(with refresh opportunity).* +- caching readed directories *to localStorage (for now) +(so if network will disconnected or something heppen with a signal, we +definitely will can work cached copy of directory listings)*; +- key binding +- disabled js support *(working in limited mode)*. +- automated minification *client js-files and onstart-reading Cloud manager files on server starting.* + +**Cloud Commander** uses all benefits of js, so if js is disabled, +we moves to *limited mode*. + +Limited-mode features: +--------------- +- only 1 panel available +- no keybinding +- no local caching +- full loading of all web page(with styles, js-scripts, html-page etc). + +Hot keys: +--------------- +In all modern web browsers (but not in IE, becouse he special) hot keys works. +There is a short list: +- Ctrl + r - reload dir content +- Ctrl + d - clear local cache (wich contains dir contents) +- Alt + q - disable key bindings +- Alt + s - get all key bindings back +- up, down, enter - filesystem navigation + + +Additional modules: +--------------- +**Cloud Commander** not using additional modules for main functionality. +But for minification and optimization tricks optional can be +assingned (and installed) modules: +- [UglifyJS] (https://github.com/mishoo/UglifyJS) +- [clean-css] (https://github.com/GoalSmashers/clean-css) +- [html-minifier] (https://github.com/kangax/html-minifier) +- [css-b64-images] (https://github.com/Filirom1/css-base64-images) \ No newline at end of file diff --git a/client.js b/client.js new file mode 100644 index 00000000..633eae40 --- /dev/null +++ b/client.js @@ -0,0 +1,716 @@ +/* Функция которая возвратит обьект CloudCommander + * @window - обьект window + * @document - обьект document + * @CloudFunc - обьект содержащий общий функционал + * клиентский и серверный + */ + +var CloudCommander=(function(){ +"use strict"; + +/* Клиентский обьект, содержащий функциональную часть*/ +var CloudClient={ + /* Конструктор CloudClient, который + * выполняет весь функционал по + * инициализации + */ + init :function(){}, + + keyBinding :function(){},/* функция нажатий обработки клавишь */ + keyBinded :false,/* оброботка нажатий клавишь установлена*/ + _loadDir :function(){}, + /* + * Функция привязываеться ко всем ссылкам и + * загружает содержимое каталогов + */ + /* Обьект для работы с кэшем */ + Cashe :{}, + + /* ПРИВАТНЫЕ ФУНКЦИИ */ + /* функция загружает json-данные о файловой системе */ + _ajaxLoad :function(){}, + /* Функция генерирует JSON из html-таблицы файлов */ + _getJSONfromFileTable :function(){}, + /* функция меняет ссыки на ajax-овые */ + _changeLinks :function(){}, + /* ОБЬЕКТЫ */ + /* обьект, который содержит функции для отображения картинок*/ + _images :{}, + /* КОНСТАНТЫ*/ + /* название css-класа текущего файла*/ + CURRENT_FILE :'current-file', + LIBDIR :'/lib', + LIBDIRCLIENT :'/lib/client' +}; + +/* + * Обьект для работы с кэшем + * в него будут включены функции для + * работы с LocalStorage, webdb, + * idexed db etc. + */ +CloudClient.Cache={ + _allowed :true, /* приватный переключатель возможности работы с кэшем */ + /* функция проверяет возможно ли работать с кэшем каким-либо образом */ + isAllowed :function(){}, + /* Тип кэша, который доступен*/ + type :{}, + /* Функция устанавливает кэш, если выбранный вид поддерживаеться браузером*/ + set :function(){}, + /* Функция достаёт кэш, если выбранный вид поддерживаеться браузером*/ + get :function(){}, + /* функция чистит весь кэш для всех каталогов*/ + clear :function(){} +}; + +/* Обьект, который содержит + * функции для отображения + * картинок + */ +CloudClient._images={ + /* Функция создаёт картинку загрузки*/ + loading :function(){ + var e=document.createElement('span'); + e.className='icon loading'; + e.id='loading-image'; + return e; +}, + + /* Функция создаёт картинку ошибки загрузки*/ + error :function(){ + var e=document.createElement('span'); + e.className='icon error'; + e.id='error-image'; + return e; + } +}; + +/* функция проверяет поддерживаеться ли localStorage */ +CloudClient.Cache.isAllowed=(function(){ + if(window.localStorage && + localStorage.setItem && + localStorage.getItem){ + CloudClient.Cache._allowed=true; + }else + { + CloudClient.Cache._allowed=false; + /* загружаем PolyFill для localStorage, + * если он не поддерживаеться браузером + * https://gist.github.com/350433 + */ + /* + CloudClient.jsload('https://raw.github.com/gist/350433/c9d3834ace63e5f5d7c8e1f6e3e2874d477cb9c1/gistfile1.js', + function(){CloudClient.Cache._allowed=true; + }); + */ + } +}); + /* если доступен localStorage и + * в нём есть нужная нам директория - + * записываем данные в него + */ +CloudClient.Cache.set=(function(pName, pData){ + if(CloudClient.Cache._allowed && pName && pData){ + localStorage.setItem(pName,pData); + } +}); +/* Если доступен Cache принимаем из него данные*/ +CloudClient.Cache.get=(function(pName){ + if(CloudClient.Cache._allowed && pName){ + return localStorage.getItem(pName); + } + else return null; +}); +/* Функция очищает кэш*/ +CloudClient.Cache.clear=(function(){ + if(CloudClient.Cache._allowed){ + localStorage.clear(); + } +}); + + +/* функция обработки нажатий клавишь */ +CloudClient.keyBinding=(function(){ + /* loading keyBinding module and start it */ + CloudClient.jsload(CloudClient.LIBDIRCLIENT+'/keyBinding.js',function(){ + CloudCommander.keyBinding(); + }); +}); + + +/* + * Функция привязываеться ко всем ссылкам и + * загружает содержимое каталогов + */ +CloudClient._loadDir=(function(pLink,pNeedRefresh){ + /* @pElem - элемент, + * для которого нужно + * выполнить загрузку + */ + return function(){ + /* показываем гиф загрузки возле пути папки сверху*/ + LoadingImage.className='icon loading';/* показываем загрузку*/ + ErrorImage.className='icon error hidden';/* прячем ошибку */ + /* если элемент задан - + * работаем с ним + */ + /* если мы попали сюда с таблицы файлов*/ + try{ + this.firstChild.nextSibling.appendChild(LoadingImage); + }catch(error){ + /* если + + * кнопка обновления + */ + try{this.firstChild.parentElement.appendChild(LoadingImage);} + catch(error){console.log(error);} + } + + var lCurrentFile=document.getElementsByClassName(CloudClient.CURRENT_FILE); + /* получаем имя каталога в котором находимся*/ + var lHref; + try{ + lHref=lCurrentFile[0].parentElement.getElementsByClassName('path')[0].innerText; + }catch(error){console.log('error');} + + lHref=CloudFunc.removeLastSlash(lHref); + var lSubstr=lHref.substr(lHref,lHref.lastIndexOf('/')); + lHref=lHref.replace(lSubstr+'/',''); + + /* загружаем содержимое каталога*/ + CloudClient._ajaxLoad(pLink, pNeedRefresh); + + /* получаем все элементы выделенной папки*/ + /* при этом, если мы нажали обновить + * или +R - ссылок мы ненайдём + * и заходить не будем + */ + var lA=this.getElementsByTagName('a'); + /* если нажали на ссылку на верхний каталог*/ + if(lA.length>0 && lA[0].innerText==='..' && + lHref!=='/'){ + /* функция устанавливает курсор на каталог + * с которого мы пришли, если мы поднялись + * в верх по файловой структуре + */ + CloudClient._currentToParent(lHref); + } + + /* что бы не переходить по ссылкам + * а грузить всё ajax'ом, + * возвращаем false на событие + * onclick + */ + return false; + }; + }); + +/* Функция устанавливает текущим файлом, тот + * на который кликнули единожды + */ +CloudClient._setCurrent=(function(){ + /* + * @pFromEnter - если мы сюда попали + * из события нажатия на энтер - + * вызоветься _loadDir + */ + return function(pFromEnter){ + var lCurrentFile=document.getElementsByClassName(CloudClient.CURRENT_FILE); + if(lCurrentFile && lCurrentFile.length > 0){ + /* если мы находимся не на + * пути и не на заголовках + */ + if(this.className!=='path' && + this.className!=='fm_header'){ + + lCurrentFile[0].className=''; + /* устанавливаем курсор на файл, + * на который нажали */ + this.className=CloudClient.CURRENT_FILE; + } + } + /* если мы попали сюда с энтера*/ + if(pFromEnter===true){ + this.ondblclick(this); + }/* если мы попали сюда от клика мышки */ + else{pFromEnter.returnValue=false;} + + /* что бы не переходить по ссылкам + * а грузить всё ajax'ом, + * возвращаем false на событие + * onclick + */ + return false; + }; + }); + +/* функция устанавливает курсор на каталог + * с которого мы пришли, если мы поднялись + * в верх по файловой структуре + * @pDirName - имя каталога с которого мы пришли + */ +CloudClient._currentToParent = (function(pDirName){ + /* опредиляем в какой мы панели: + * правой или левой + */ + var lCurrentFile=document.getElementsByClassName(CloudClient.CURRENT_FILE); + var lPanel; + try{ + lPanel=lCurrentFile[0].parentElement.id; + }catch(error){console.log("Current file not found\n"+error);} + /* убираем слэш с имени каталога*/ + pDirName=pDirName.replace('/',''); + /* ищем файл с таким именем*/ + lPanel=document.getElementById(lPanel); + if(!lPanel)return; + + var lLi=lPanel.getElementsByTagName('li'); + for(var i=0;i0)lCurrentFile[0].className=''; + + lLi[i].className=CloudClient.CURRENT_FILE; + } + } +}); + +/* глобальные переменные */ +var LoadingImage; +var ErrorImage; + +var $; +var CloudFunc; +/* Конструктор CloudClient, который + * выполняет весь функционал по + * инициализации + */ +CloudClient.init=(function() +{ + /* меняем title + * если js включен - имена папок отображать необязательно... + * а может и обязательно при переходе, можно будет это сделать + */ + var lTitle=document.getElementsByTagName('title'); + if(lTitle.length>0)lTitle[0].innerText='Cloud Commander'; + + /* загружаем jquery: */ + CloudClient.jsload('//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js',function(){ + /* сохраняем переменную jQuery себе в область видимости */ + $=window.jQuery; + if(!window.jQuery)CloudClient.jsload('jquery.min.js', + function(){ + $=window.jQuery; + }); + }); + + /* загружаем общие функции для клиента и сервера*/ + CloudClient.jsload(CloudClient.LIBDIR+'/cloudfunc.js',function(){ + /* берём из обьекта window общий с сервером функционал */ + CloudFunc=window.CloudFunc; + + /* меняем ссылки на ajax'овые*/ + CloudClient._changeLinks(CloudFunc.LEFTPANEL); + CloudClient._changeLinks(CloudFunc.RIGHTPANEL); + + /* устанавливаем переменную доступности кэша*/ + CloudClient.Cache.isAllowed(); + /* Устанавливаем кэш корневого каталога */ + if(!CloudClient.Cache.get('/'))CloudClient.Cache.set('/',CloudClient._getJSONfromFileTable()); + } + ); + + LoadingImage=CloudClient._images.loading(); + /* загружаем иконку загрузки возле кнопки обновления дерева каталогов*/ + try{ + document.getElementsByClassName('path')[0].getElementsByTagName('a')[0].appendChild(LoadingImage); + LoadingImage.className+=' hidden'; /* прячем её */ + }catch(error){console.log(error);} + ErrorImage=CloudClient._images.error(); + + /* устанавливаем размер высоты таблицы файлов + * исходя из размеров разрешения экрана + */ + + /* формируем и округляем высоту экрана + * при разрешениии 1024x1280: + * 658 -> 700 + */ + + var lHeight=window.screen.height - (window.screen.height/3).toFixed(); + lHeight=(lHeight/100).toFixed()*100; + + var lFm=document.getElementById('fm'); + if(lFm)lFm.style.cssText='height:' + + lHeight + + 'px'; + + /* выделяем строку с первым файлом */ + var lFmHeader=document.getElementsByClassName('fm_header'); + if(lFmHeader && lFmHeader[0].nextSibling) + lFmHeader[0].nextSibling.className=CloudClient.CURRENT_FILE; + + /* показываем элементы, которые будут работать только, если есть js */ + var lFM=document.getElementById('fm'); + if(lFM)lFm.className='localstorage'; + + /* если есть js - показываем правую панель*/ + var lRight=document.getElementById('right'); + if(lRight)lRight.className=lRight.className.replace('hidden',''); + + CloudClient.cssSet({id:'show_2panels', + element:document.head, + inner:'#left{width:45%;}' + }); +}); + +/* функция меняет ссыки на ajax-овые */ +CloudClient._changeLinks = function(pPanelID) +{ + /* назначаем кнопку очистить кэш и показываем её*/ + var lClearcache=document.getElementById('clear-cache'); + if(lClearcache)lClearcache.onclick=CloudClient.Cache.clear; + + /* меняем ссылки на ajax-запросы */ + var lPanel=document.getElementById(pPanelID); + var a=lPanel.getElementsByTagName('a'); + + /* Если нажмут на кнопку перезагрузить страниц - её нужно будет обязательно + * перезагрузить + */ + /* номер ссылки очистки кэша*/ + //var lCLEARICON=0; + /* номер ссылки иконки обновления страницы */ + var lREFRESHICON=0; + + /* путь в ссылке, который говорит + * что js отключен + */ + var lNoJS_s = CloudFunc.NOJS; + var lFS_s = CloudFunc.FS; + + for(var i=0;i=3){ + element.onload=pFunc; + if(arguments.length>=4){ + element.style.cssText=pStyle; + } + } + //document.body + pElement.appendChild(element); + return element;//'elem '+src+' loaded'; + } + /* если js-файл уже загружен + * запускаем функцию onload + */ + else if(pFunc){ + try{ + pFunc(); + }catch(error){console.log(error);} + } +}; + +/* Функция загружает js-файл */ +CloudClient.jsload = function(pSrc,pFunc,pStyle,pId) +{ + CloudClient._anyload('script',pSrc,pFunc,pStyle,pId,document.body); +}; +/* Функция создаёт елемент style и записывает туда стили + * @pParams_o - структура параметров, заполняеться таким + * образом: {src: ' ',func: '', id: '', element: '', inner: ''} + * все параметры опциональны + */ +CloudClient.cssSet = function(pParams_o){ + var lElem=CloudClient._anyload('style', + pParams_o.src, + pParams_o.func, + pParams_o.style, + pParams_o.id, + pParams_o.element?pParams_o.element:document.body); + lElem.innerText=pParams_o.inner; +}; + +/* + * Функция генерирует JSON из html-таблицы файлов + */ +/* + * Используеться при первом заходе в корень + */ +CloudClient._getJSONfromFileTable=function() +{ + var lLeft=document.getElementById('left'); + + + //var lPath=document.getElementById('path').innerText; + var lPath=document.getElementsByClassName('path')[0].innerText; + var lFileTable=[{path:lPath,size:'dir'}]; + var lLI=lLeft.getElementsByTagName('li'); + + var j=1;/* счётчик реальных файлов */ + var i=1;/* счётчик элементов файлов в DOM */ + /* Если путь отличный от корневного + * второй элемент li - это ссылка на верхний + * каталог '..' + */ + i=2;/* пропускам Path и Header*/ + + + for(;i<\/script>'); +*/ + +/* Клиентский обьект, содержащий функциональную часть*/ +var CloudClient={ + /* Конструктор CloudClient, который + * выполняет весь функционал по + * инициализации + */ + init :function(){}, + + keyBinding :function(){},/* функция нажатий обработки клавишь */ + keyBinded :false,/* оброботка нажатий клавишь установлена*/ + _loadDir :function(){}, + /* + * Функция привязываеться ко всем ссылкам и + * загружает содержимое каталогов + */ + /* Обьект для работы с кэшем */ + Cashe :{}, + + /* ПРИВАТНЫЕ ФУНКЦИИ */ + /* функция загружает json-данные о файловой системе */ + _ajaxLoad :function(){}, + /* Функция генерирует JSON из html-таблицы файлов */ + _getJSONfromFileTable :function(){}, + /* функция меняет ссыки на ajax-овые */ + _changeLinks :function(){}, + /* ОБЬЕКТЫ */ + /* обьект, который содержит функции для отображения картинок*/ + _images :{}, + /* КОНСТАНТЫ*/ + /* название css-класа текущего файла*/ + CURRENT_FILE :'current-file', + LIBDIR :'/lib', + LIBDIRCLIENT :'/lib/client' +}; + +/* + * Обьект для работы с кэшем + * в него будут включены функции для + * работы с LocalStorage, webdb, + * idexed db etc. + */ +CloudClient.Cache={ + _allowed :true, /* приватный переключатель возможности работы с кэшем */ + /* функция проверяет возможно ли работать с кэшем каким-либо образом */ + isAllowed :function(){}, + /* Тип кэша, который доступен*/ + type :{}, + /* Функция устанавливает кэш, если выбранный вид поддерживаеться браузером*/ + set :function(){}, + /* Функция достаёт кэш, если выбранный вид поддерживаеться браузером*/ + get :function(){}, + /* функция чистит весь кэш для всех каталогов*/ + clear :function(){} +}; + +/* Обьект, который содержит + * функции для отображения + * картинок + */ +CloudClient._images={ + /* Функция создаёт картинку загрузки*/ + loading :function(){ + var e=document.createElement('span'); + e.className='icon loading'; + e.id='loading-image'; + return e; +}, + + /* Функция создаёт картинку ошибки загрузки*/ + error :function(){ + var e=document.createElement('span'); + e.className='icon error'; + e.id='error-image'; + return e; + } +}; + +/* функция проверяет поддерживаеться ли localStorage */ +CloudClient.Cache.isAllowed=(function(){ + if(window.localStorage && + localStorage.setItem && + localStorage.getItem){ + CloudClient.Cache._allowed=true; + }else + { + CloudClient.Cache._allowed=false; + /* загружаем PolyFill для localStorage, + * если он не поддерживаеться браузером + * https://gist.github.com/350433 + */ + /* + CloudClient.jsload('https://raw.github.com/gist/350433/c9d3834ace63e5f5d7c8e1f6e3e2874d477cb9c1/gistfile1.js', + function(){CloudClient.Cache._allowed=true; + }); + */ + } +}); + /* если доступен localStorage и + * в нём есть нужная нам директория - + * записываем данные в него + */ +CloudClient.Cache.set=(function(pName, pData){ + if(CloudClient.Cache._allowed && pName && pData){ + localStorage.setItem(pName,pData); + } +}); +/* Если доступен Cache принимаем из него данные*/ +CloudClient.Cache.get=(function(pName){ + if(CloudClient.Cache._allowed && pName){ + return localStorage.getItem(pName); + } + else return null; +}); +/* Функция очищает кэш*/ +CloudClient.Cache.clear=(function(){ + if(CloudClient.Cache._allowed){ + localStorage.clear(); + } +}); + + +/* функция обработки нажатий клавишь */ +CloudClient.keyBinding=(function(){ + /* loading keyBinding module and start it */ + CloudClient.jsload(CloudClient.LIBDIRCLIENT+'/keyBinding.js',function(){ + CloudCommander.keyBinding(); + }); +}); + + +/* + * Функция привязываеться ко всем ссылкам и + * загружает содержимое каталогов + */ +CloudClient._loadDir=(function(pLink,pNeedRefresh){ + /* @pElem - элемент, + * для которого нужно + * выполнить загрузку + */ + return function(){ + /* показываем гиф загрузки возле пути папки сверху*/ + LoadingImage.className='icon loading';/* показываем загрузку*/ + ErrorImage.className='icon error hidden';/* прячем ошибку */ + /* если элемент задан - + * работаем с ним + */ + /* если мы попали сюда с таблицы файлов*/ + try{ + this.firstChild.nextSibling.appendChild(LoadingImage); + }catch(error){ + /* если + + * кнопка обновления + */ + try{this.firstChild.parentElement.appendChild(LoadingImage);} + catch(error){console.log(error);} + } + + var lCurrentFile=document.getElementsByClassName(CloudClient.CURRENT_FILE); + /* получаем имя каталога в котором находимся*/ + var lHref; + try{ + lHref=lCurrentFile[0].parentElement.getElementsByClassName('path')[0].innerText; + }catch(error){console.log('error');} + + lHref=CloudFunc.removeLastSlash(lHref); + var lSubstr=lHref.substr(lHref,lHref.lastIndexOf('/')); + lHref=lHref.replace(lSubstr+'/',''); + + /* загружаем содержимое каталога*/ + CloudClient._ajaxLoad(pLink, pNeedRefresh); + + /* получаем все элементы выделенной папки*/ + /* при этом, если мы нажали обновить + * или +R - ссылок мы ненайдём + * и заходить не будем + */ + var lA=this.getElementsByTagName('a'); + /* если нажали на ссылку на верхний каталог*/ + if(lA.length>0 && lA[0].innerText==='..' && + lHref!=='/'){ + /* функция устанавливает курсор на каталог + * с которого мы пришли, если мы поднялись + * в верх по файловой структуре + */ + CloudClient._currentToParent(lHref); + } + + /* что бы не переходить по ссылкам + * а грузить всё ajax'ом, + * возвращаем false на событие + * onclick + */ + return false; + }; + }); + +/* Функция устанавливает текущим файлом, тот + * на который кликнули единожды + */ +CloudClient._setCurrent=(function(){ + /* + * @pFromEnter - если мы сюда попали + * из события нажатия на энтер - + * вызоветься _loadDir + */ + return function(pFromEnter){ + var lCurrentFile=document.getElementsByClassName(CloudClient.CURRENT_FILE); + if(lCurrentFile && lCurrentFile.length > 0){ + /* если мы находимся не на + * пути и не на заголовках + */ + if(this.className!=='path' && + this.className!=='fm_header'){ + + lCurrentFile[0].className=''; + /* устанавливаем курсор на файл, + * на который нажали */ + this.className=CloudClient.CURRENT_FILE; + } + } + /* если мы попали сюда с энтера*/ + if(pFromEnter===true){ + this.ondblclick(this); + }/* если мы попали сюда от клика мышки */ + else{pFromEnter.returnValue=false;} + + /* что бы не переходить по ссылкам + * а грузить всё ajax'ом, + * возвращаем false на событие + * onclick + */ + return false; + }; + }); + +/* функция устанавливает курсор на каталог + * с которого мы пришли, если мы поднялись + * в верх по файловой структуре + * @pDirName - имя каталога с которого мы пришли + */ +CloudClient._currentToParent = (function(pDirName){ + /* опредиляем в какой мы панели: + * правой или левой + */ + var lCurrentFile=document.getElementsByClassName(CloudClient.CURRENT_FILE); + var lPanel; + try{ + lPanel=lCurrentFile[0].parentElement.id; + }catch(error){console.log("Current file not found\n"+error);} + /* убираем слэш с имени каталога*/ + pDirName=pDirName.replace('/',''); + /* ищем файл с таким именем*/ + lPanel=document.getElementById(lPanel); + if(!lPanel)return; + + var lLi=lPanel.getElementsByTagName('li'); + for(var i=0;i0)lCurrentFile[0].className=''; + + lLi[i].className=CloudClient.CURRENT_FILE; + } + } +}); + +/* глобальные переменные */ +var LoadingImage; +var ErrorImage; + +var $; +var CloudFunc; +/* Конструктор CloudClient, который + * выполняет весь функционал по + * инициализации + */ +CloudClient.init=(function() +{ + /* меняем title + * если js включен - имена папок отображать необязательно... + * а может и обязательно при переходе, можно будет это сделать + */ + var lTitle=document.getElementsByTagName('title'); + if(lTitle.length>0)lTitle[0].innerText='Cloud Commander'; + + /* загружаем jquery: */ + CloudClient.jsload('//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js',function(){ + /* сохраняем переменную jQuery себе в область видимости */ + $=window.jQuery; + if(!window.jQuery)CloudClient.jsload('jquery.min.js', + function(){ + $=window.jQuery; + }); + }); + + /* загружаем общие функции для клиента и сервера*/ + CloudClient.jsload(CloudClient.LIBDIR+'/cloudfunc.js',function(){ + /* берём из обьекта window общий с сервером функционал */ + CloudFunc=window.CloudFunc; + + /* меняем ссылки на ajax'овые*/ + CloudClient._changeLinks(CloudFunc.LEFTPANEL); + CloudClient._changeLinks(CloudFunc.RIGHTPANEL); + + /* устанавливаем переменную доступности кэша*/ + CloudClient.Cache.isAllowed(); + /* Устанавливаем кэш корневого каталога */ + if(!CloudClient.Cache.get('/'))CloudClient.Cache.set('/',CloudClient._getJSONfromFileTable()); + } + ); + + LoadingImage=CloudClient._images.loading(); + /* загружаем иконку загрузки возле кнопки обновления дерева каталогов*/ + try{ + document.getElementsByClassName('path')[0].getElementsByTagName('a')[0].appendChild(LoadingImage); + LoadingImage.className+=' hidden'; /* прячем её */ + }catch(error){console.log(error);} + ErrorImage=CloudClient._images.error(); + + /* устанавливаем размер высоты таблицы файлов + * исходя из размеров разрешения экрана + */ + + /* формируем и округляем высоту экрана + * при разрешениии 1024x1280: + * 658 -> 700 + */ + + var lHeight=window.screen.height - (window.screen.height/3).toFixed(); + lHeight=(lHeight/100).toFixed()*100; + + var lFm=document.getElementById('fm'); + if(lFm)lFm.style.cssText='height:' + + lHeight + + 'px'; + + /* выделяем строку с первым файлом */ + var lFmHeader=document.getElementsByClassName('fm_header'); + if(lFmHeader && lFmHeader[0].nextSibling) + lFmHeader[0].nextSibling.className=CloudClient.CURRENT_FILE; + + /* показываем элементы, которые будут работать только, если есть js */ + var lFM=document.getElementById('fm'); + if(lFM)lFm.className='localstorage'; + + /* если есть js - показываем правую панель*/ + var lRight=document.getElementById('right'); + if(lRight)lRight.className=lRight.className.replace('hidden',''); + + CloudClient.cssSet({id:'show_2panels', + element:document.head, + inner:'#left{width:45%;}' + }); +}); + +/* функция меняет ссыки на ajax-овые */ +CloudClient._changeLinks = function(pPanelID) +{ + /* назначаем кнопку очистить кэш и показываем её*/ + var lClearcache=document.getElementById('clear-cache'); + if(lClearcache)lClearcache.onclick=CloudClient.Cache.clear; + + /* меняем ссылки на ajax-запросы */ + var lPanel=document.getElementById(pPanelID); + var a=lPanel.getElementsByTagName('a'); + + /* Если нажмут на кнопку перезагрузить страниц - её нужно будет обязательно + * перезагрузить + */ + /* номер ссылки очистки кэша*/ + //var lCLEARICON=0; + /* номер ссылки иконки обновления страницы */ + var lREFRESHICON=0; + + /* путь в ссылке, который говорит + * что js отключен + */ + var lNoJS_s = CloudFunc.NOJS; + var lFS_s = CloudFunc.FS; + + for(var i=0;i=3){ + element.onload=pFunc; + if(arguments.length>=4){ + element.style.cssText=pStyle; + } + } + //document.body + pElement.appendChild(element); + return element;//'elem '+src+' loaded'; + } + /* если js-файл уже загружен + * запускаем функцию onload + */ + else if(pFunc){ + try{ + pFunc(); + }catch(error){console.log(error);} + } +}; + +/* Функция загружает js-файл */ +CloudClient.jsload = function(pSrc,pFunc,pStyle,pId) +{ + CloudClient._anyload('script',pSrc,pFunc,pStyle,pId,document.body); +}; +/* Функция создаёт елемент style и записывает туда стили + * @pParams_o - структура параметров, заполняеться таким + * образом: {src: ' ',func: '', id: '', element: '', inner: ''} + * все параметры опциональны + */ +CloudClient.cssSet = function(pParams_o){ + var lElem=CloudClient._anyload('style', + pParams_o.src, + pParams_o.func, + pParams_o.style, + pParams_o.id, + pParams_o.element?pParams_o.element:document.body); + lElem.innerText=pParams_o.inner; +}; + +/* + * Функция генерирует JSON из html-таблицы файлов + */ +/* + * Используеться при первом заходе в корень + */ +CloudClient._getJSONfromFileTable=function() +{ + var lLeft=document.getElementById('left'); + + + //var lPath=document.getElementById('path').innerText; + var lPath=document.getElementsByClassName('path')[0].innerText; + var lFileTable=[{path:lPath,size:'dir'}]; + var lLI=lLeft.getElementsByTagName('li'); + + var j=1;/* счётчик реальных файлов */ + var i=1;/* счётчик элементов файлов в DOM */ + /* Если путь отличный от корневного + * второй элемент li - это ссылка на верхний + * каталог '..' + */ + i=2;/* пропускам Path и Header*/ + + + for(;i + + + + + + Cloud Commander + + + + + + + + + + +
+
+ + + + \ No newline at end of file diff --git a/cloudcmd1/1/package.json b/cloudcmd1/1/package.json new file mode 100644 index 00000000..5c67dd25 --- /dev/null +++ b/cloudcmd1/1/package.json @@ -0,0 +1,11 @@ +{ + "name": "cloudcmd", + "version": "0.0.1-9", + "scripts": { + "start": "server.js" + }, + "engines": { + "node": "0.6.x" + }, + "subdomain": "cloudcmd" +} \ No newline at end of file diff --git a/cloudcmd1/1/package2.json b/cloudcmd1/1/package2.json new file mode 100644 index 00000000..f2d59387 --- /dev/null +++ b/cloudcmd1/1/package2.json @@ -0,0 +1,12 @@ +{ + "name": "cloudcmd", + "version": "0.0.1-3", + "scripts": { + + "start": "server.js" + }, + "engines": { + "node": "0.6.x" + }, + "subdomain": "cloudcmd" +} diff --git a/cloudcmd1/1/reset.css b/cloudcmd1/1/reset.css new file mode 100644 index 00000000..a24c865b --- /dev/null +++ b/cloudcmd1/1/reset.css @@ -0,0 +1,100 @@ +/* ============================================================================= + HTML5 display definitions + ========================================================================== */ + +/* +article, aside, details, figcaption, figure, footer, header, hgroup, nav, section { display: block; } +audio, canvas, video { display: inline-block; *display: inline; *zoom: 1; } +audio:not([controls]) { display: none; } +[hidden] { display: none; } +*/ + +/* ============================================================================= + Base + ========================================================================== */ + +/* + * 1. Correct text resizing oddly in IE6/7 when body font-size is set using em units + * 2. Prevent iOS text size adjust on device orientation change, without disabling user zoom: h5bp.com/g + */ + +html { font-size: 100%; -webkit-text-size-adjust: 100%; -ms-text-size-adjust: 100%; font-family: sans-serif; color: #222;} +body { margin: 0; font-size: 1em; line-height: 1.4; } + +/* + * Remove text-shadow in selection highlight: h5bp.com/i + * These selection declarations have to be separate + * Also: hot pink! (or customize the background color to match your design) + */ +/* +::-moz-selection { background: #fe57a1; color: #fff; text-shadow: none; } + ::selection { background: #fe57a1; color: #fff; text-shadow: none; } +*/ +::selection { text-shadow: none; opacity: 0;} + + +/* ============================================================================= + Links + ========================================================================== */ + +a {text-decoration:none; color: #00e; } +a:visited { color: #551a8b; } +a:hover { color: #06e; } +a:focus { outline: thin dotted; } + +/* Improve readability when focused and hovered in all browsers: h5bp.com/h */ +a:hover, a:active { outline: 0; } + +ul{ margin: 1em 0; padding: 0 0 0 40px; } + +/* + * 1. Display hand cursor for clickable form elements + * 2. Allow styling of clickable form elements in iOS + * 3. Correct inner spacing displayed oddly in IE7 (doesn't effect IE6) + */ + + +/* ============================================================================= + Chrome Frame Prompt + ========================================================================== */ + +.chromeframe { margin: 0.2em 0; background: #ccc; color: black; padding: 0.2em 0; } + + +/* ==|== non-semantic helper classes ======================================== + Please define your styles before this section. + ========================================================================== */ + +/* For image replacement */ +.ir { display: block; border: 0; text-indent: -999em; overflow: hidden; background-color: transparent; background-repeat: no-repeat; text-align: left; direction: ltr; *line-height: 0; } +.ir br { display: none; } + +/* Hide from both screenreaders and browsers: h5bp.com/u */ +.hidden { display: none !important; visibility: hidden; } + +/* Hide only visually, but have it available for screenreaders: h5bp.com/v */ +.visuallyhidden { border: 0; clip: rect(0 0 0 0); height: 1px; margin: -1px; overflow: hidden; padding: 0; position: absolute; width: 1px; } + +/* Extends the .visuallyhidden class to allow the element to be focusable when navigated to via the keyboard: h5bp.com/p */ +.visuallyhidden.focusable:active, .visuallyhidden.focusable:focus { clip: auto; height: auto; margin: 0; overflow: visible; position: static; width: auto; } + +/* Hide visually and from screenreaders, but maintain layout */ +.invisible { visibility: hidden; } + +/* Contain floats: h5bp.com/q */ +.clearfix:before, .clearfix:after { content: ""; display: table; } +.clearfix:after { clear: both; } +.clearfix { *zoom: 1; } + +/* ==|== print styles ======================================================= + Print styles. + Inlined to avoid required HTTP connection: h5bp.com/r + ========================================================================== */ + +@media print { + * { background: transparent !important; color: black !important; box-shadow:none !important; text-shadow: none !important; filter:none !important; -ms-filter: none !important; } /* Black prints faster: h5bp.com/s */ + a, a:visited { text-decoration: underline; } + a[href]:after { content: " (" attr(href) ")"; } + .ir a:after, a[href^="javascript:"]:after, a[href^="#"]:after { content: ""; } /* Don't show links for images, or javascript/internal links */ + @page { margin: 0.5cm; } +} \ No newline at end of file diff --git a/cloudcmd1/1/server.js b/cloudcmd1/1/server.js new file mode 100644 index 00000000..2839b1ef --- /dev/null +++ b/cloudcmd1/1/server.js @@ -0,0 +1,635 @@ +"use strict"; + +/* Обьект содержащий все функции и переменные + * серверной части Cloud Commander'а + */ +var CloudServer={ + /* функция, которая генерирует заголовки + * файлов, отправляемые сервером клиенту + */ + generateHeaders :function(){}, + /* функция высылает + * данные клиенту + */ + sendResponse :function(){}, + /* Структура содержащая функции, + * и переменные, в которых + * говориться о поддерживаемых + * браузером технологиях + */ + BrowserSuport :{}, + /* Обьект для работы с кэшем */ + Cashe :{}, + /* Обьект через который + * выполняеться сжатие + * скриптов и стилей + */ + Minify :{}, + /* Асоциативный масив обьектов для + * работы с ответами сервера + * высылаемыми на запрос о файле и + * хранащий информацию в виде + * Responces[name]=responce; + */ + Responses :{}, + + /* ПЕРЕМЕННЫЕ */ + /* Поддержка браузером JS*/ + NoJS :true, + /* Поддержка gzip-сжатия + * браузером + */ + Gzip :undefined, + + /* КОНСТАНТЫ */ + /* index.html */ + INDEX :'index.html', + /* name of direcotory with libs */ + LIBDIR :'./lib', + LIBDIRSERVER :'./lib/server' +}; + +/* + * Обьект для работы с кэшем + * аналог клиентского обьекта + * с тем отличием, что в нём + * будут храниться серверные + * данные, такие как файлы + * отдаваемые клиенту + * (файлы проэкта по большому + * счёту, для ускорения + * первичной загрузки) + */ +CloudServer.Cache={ + _allowed :true, /* приватный переключатель возможности работы с кэшем */ + /* данные в которых храняться файлы + * в формате <поле> : <значение> + * _data[name]=pData; + * одному имени соответствуют + * одни данные + */ + _data :{}, + + /* функция говорит можно ли работать с кэшем */ + isAllowed :(function(){ + return CloudServer.Cache._allowed; + }), + /* функция устанавливает возможность работать с кэшем */ + setAllowed :(function(pAllowed){ + CloudServer.Cache._allowed=pAllowed; + }), + /* Если доступен кэш + * сохраняем в него данные + */ + set :(function(pName, pData){ + if(CloudServer.Cache._allowed && pName && pData){ + CloudServer.Cache._data[pName]=pData; + } + }), + /* Если доступен Cache принимаем из него данные*/ + get :(function(pName){ + if(CloudServer.Cache._allowed && pName){ + return CloudServer.Cache._data[pName]; + } + else return null; + }), + + /* Функция очищает кэш*/ + clear :(function(){ + if(CloudServer.Cache._allowed){ + CloudServer.Cache._data={}; + } + }) +}; + +/* Обьект для сжатия скриптов и стилей + * по умолчанию - сжимаються + */ +CloudServer.Minify={ + /* приватный переключатель минимизации */ + _allowed :{css:true,js:true,html:true, img: true}, + + /* функция разрешает или + * запрещает минимизировать + * css/js/html + * @pAllowed: - структура, в которой + * передаються параметры + * минификации, вида + * {js:true,css:true,html:false; img:true} + * img отвечает за перевод картинок в base64 + * и сохранение их в css-файл + */ + setAllowed :(function(pAllowed){ + if(pAllowed){ + this._allowed.css=pAllowed.css; + this._allowed.js=pAllowed.js; + this._allowed.html=pAllowed.html; + this._allowed.img=pAllowed.img; + } + }), + + /* + * Функция минимизирует css/js/html + * если установлены параметры минимизации + */ + doit :(function(){ + if(this._allowed.css || + this._allowed.js || + this._allowed.html){ + var lMinify = require(CloudServer.LIBDIRSERVER+'/minify'); + + this.done.js=this._allowed.js?lMinify.jsScripts():false; + this.done.html=this._allowed.html?lMinify.html():false; + this.done.css=this._allowed.css?lMinify.cssStyles(this._allowed.img):false; + } + }), + /* свойство показывающее случилась ли ошибка*/ + done:{js: false,css: false, html:false} +}; + + +var LeftDir='/'; +var RightDir=LeftDir; +/* + var Path = require('path'); +*/ /* модуль для работы с путями*/ + +var Fs = require('fs'); /* модуль для работы с файловой системой*/ + +var Zlib; +/* node v0.4 not contains zlib + */ +try{ + Zlib = require('zlib'); /* модуль для сжатия данных gzip-ом*/ +}catch(error){ + Zlib=undefined; + console.log('to use gzip-commpression' + + 'you should install zlib module\n' + + 'npm install zlib'); +} +var CloudFunc = require(CloudServer.LIBDIR + + (CloudServer.Minify.done.js?/* если стоит минификация*/ + '/cloudfunc.min':/* добавляем сжатый - иначе обычный */ + '/cloudfunc')); /* модуль с функциями */ +/* конструктор*/ +CloudServer.init=(function(){ + /* Переменная в которой храниться кэш*/ + CloudServer.Cache.setAllowed(true); + /* Change default parameters of + * js/css/html minification + */ + CloudServer.Minify.setAllowed({ + js:true, + css:true, + html:true, + img:true + }); + /* Если нужно минимизируем скрипты */ + CloudServer.Minify.doit(); +}); + + +/* создаём сервер на порту 31337*/ +CloudServer.start=function() +{ + CloudServer.init(); + + var http = require('http'); + http.createServer(CloudServer._controller).listen(process.env.PORT || + process.env.VCAP_APP_PORT /* cloudfoundry */ || + 31337, + '0.0.0.0' || '127.0.0.1'); + console.log('Cloud Commander server running at http://127.0.0.1:'+ + (process.env.PORT===undefined?31337:process.env.PORT)); +}; + + +/* Функция создаёт заголовки файлов + * в зависимости от расширения файла + * перед отправкой их клиенту + * @pName - имя файла + * @pGzip - данные сжаты gzip'ом + */ +CloudServer.generateHeaders = function(pName, pGzip){ + var lType=''; + /* высылаем заголовок в зависимости от типа файла */ + /* если расширение у файла css - + * загружаем стили + */ + if(CloudFunc.checkExtension(pName,'css')) + lType='text/css'; + /* загружаем js */ + else if(CloudFunc.checkExtension(pName,'js')) + lType='text/javascript'; + /* загружаем картинки*/ + else if(CloudFunc.checkExtension(pName,'png')) + lType='image/png'; + /* загружаем json*/ + else if(CloudFunc.checkExtension(pName,'json')) + lType='application/json'; + else if(CloudFunc.checkExtension(pName,'html')) + lType='text/html'; + else if(CloudFunc.checkExtension(pName,'appcache')) + lType='text/cache-manifest'; + /* если это неизвестный тип файла - + * высылаем его просто как текст + */ + else lType='text/plain'; + + return { + /* if type of file any, but img - + * then we shoud specify charset + */ + 'Content-Type': lType + (lType.indexOf('img')<0?'; charset=UTF-8':''), + 'cache-control': 'max-age='+(31337*21), + 'last-modified': new Date().toString(), + 'content-encoding': pGzip?'gzip':'', + /* https://developers.google.com/speed/docs/best-practices/caching?hl=ru#LeverageProxyCaching */ + 'Vary': 'Accept-Encoding' + }; +}; + +/* + * Главная функция, через которую проихсодит + * взаимодействие, обмен данными с клиентом + * @req - запрос клиента (Request) + * @res - ответ сервера (Response) + */ +CloudServer._controller=function(pReq, pRes) +{ + /* Читаем содержимое папки, + переданное в url + */ + var url = require("url"); + var pathname = url.parse(pReq.url).pathname; + console.log('pathname: '+pathname); + + /* получаем поддерживаемые браузером кодировки*/ + var lAcceptEncoding = pReq.headers['accept-encoding']; + /* запоминаем поддерживает ли браузер + * gzip-сжатие при каждом обращении к серверу + * и доступен ли нам модуль zlib + */ + if (lAcceptEncoding && + lAcceptEncoding.match(/\bgzip\b/) && + Zlib){ + CloudServer.Gzip=true; + }else + CloudServer.Gzip=false; + /* путь в ссылке, который говорит + * что js отключен + */ + var lNoJS_s=CloudFunc.NOJS; + var lFS_s=CloudFunc.FS; + + if(pathname!=='/favicon.ico') + { + console.log("request for " + pathname + " received..."); + var lName; + + /* если в пути нет информации ни о ФС, + * ни об отсутствии js, + * ни о том, что это корневой + * каталог - загружаем файлы проэкта + */ + if(pathname.indexOf(lFS_s)<0 && + pathname.indexOf(lNoJS_s)<0 && + pathname!=='/'){ + /* если имена файлов проекта - загружаем их*/ + /* убираем слеш и читаем файл с текущец директории*/ + //lName=Path.basename(pathname); + + /* добавляем текующий каталог к пути */ + lName='.'+pathname; + console.log('reading '+lName); + /* сохраняем указатель на responce и имя */ + CloudServer.Responses[lName]=pRes; + + /* Берём значение из кэша + * сжатый файл - если gzip-поддерживаеться браузером + * не сжатый - в обратном случае + */ + var lFileData=CloudServer.Cache.get(CloudServer.Gzip?(lName+'_gzip'):lName); + + var lReadFileFunc_f=CloudServer.getReadFileFunc(lName); + /* если там что-то есть передаём данные в функцию + * readFile + */ + if(lFileData){ + console.log('readed from cache'); + /* передаём данные с кэша, + * если gzip включен - сжатые + * в обратном случае - несжатые + */ + lReadFileFunc_f(undefined,lFileData,true); + } + else Fs.readFile(lName,lReadFileFunc_f); + + }else{/* если мы имеем дело с файловой системой*/ + /* если путь не начинаеться с no-js - значит + * js включен + */ + /* убираем пометку cloud, без которой c9.io + * не работает поскольку путь из двух слешей + * (/fs/no-js/) - очень короткий, нужно + * длиннее + */ + + if(pathname.indexOf(lNoJS_s)!==lFS_s.length && pathname!=='/'){ + CloudServer.NoJS=false; + }else pathname=pathname.replace(lNoJS_s,''); + + /* убираем индекс файловой системы */ + if(pathname.indexOf(lFS_s)===0){ + pathname=pathname.replace(lFS_s,''); + /* если посетитель только зашел на сайт + * no-js будет пустым, как и fs + */ + /* если в пути нету fs - посетитель только зашел на сайт + * загружаем его полностью. + */ + }else CloudServer.NoJS=true; + /* если в итоге путь пустой + * делаем его корневым + */ + if(pathname==='')pathname='/'; + + RightDir=pathname; + LeftDir=pathname; + + /* если встретиться пробел - + * меня код символа пробела на пробел + */ + + LeftDir=CloudFunc.replaceSpaces(LeftDir); + RightDir=CloudFunc.replaceSpaces(RightDir); + + /* Проверяем с папкой ли мы имеем дело */ + + /* читаем сновные данные о файле */ + var lStat; + try{ + lStat=Fs.statSync(LeftDir); + }catch(error){ + console.log(error); + CloudServer.Responses[LeftDir]=pRes; + CloudServer.sendResponse('OK',error.toString(),LeftDir); + } + /* если это каталог - + * читаем его содержимое + */ + try{ + /* если установлено сжатие + * меняем название html-файла и + * загружаем сжатый html-файл в дальнейшем + */ + CloudServer.INDEX=(CloudServer.Minify.done.html?'index.min.html':CloudServer.INDEX); + /* + * сохраним указатель на response + */ + CloudServer.Responses[CloudServer.INDEX]=pRes; + if(lStat.isDirectory()) + Fs.readdir(LeftDir,CloudServer._readDir); + /* отдаём файл */ + else if(lStat.isFile()){ + CloudServer.Responses[LeftDir]=pRes; + Fs.readFile(LeftDir,CloudServer.getReadFileFunc(LeftDir)); + console.log('reading file: '+LeftDir); + } + }catch(error){console.log(error);} + } + } +}; + +/* Функция читает ссылку или выводит информацию об ошибке*/ +CloudServer._readDir=function (pError, pFiles) +{ + if(!pError) + { + /* данные о файлах в формате JSON*/ + var lJSON=[]; + var lJSONFile={}; + /* Если мы не в корне добавляем слеш к будующим ссылкам */ + if(LeftDir!=='/') + { + RightDir+='/'; + LeftDir+='/'; + } + + pFiles=pFiles.sort(); + + lJSON[0]={path:LeftDir,size:'dir'}; + var fReturnFalse=function returnFalse(){return false;}; + for(var i=0;i','') + .replace('style.css','all.min.css') + :lIndex; + + lIndex = CloudServer.Minify.done.js?lIndex.replace('client.js','client.min.js'):lIndex; + + lIndex=lIndex.toString().replace('
','
'+lList); + /* меняем title */ + lIndex=lIndex.replace('Cloud Commander', + ''+CloudFunc.setTitle()+''); + /* отображаем панель быстрых клавишь */ + lList=lIndex; + /* если браузер поддерживает gzip-сжатие*/ + lHeader=CloudServer.generateHeaders('text/html',CloudServer.Gzip); + }catch(error){console.log(error);} + }else{ + /* в обычном режиме(когда js включен + * высылаем json-структуру файлов + * с соответствующими заголовками + */ + lList=JSON.stringify(lJSON); + lHeader=CloudServer.generateHeaders('application/json',CloudServer.Gzip); + } + /* если браузер поддерживает gzip-сжатие - сжимаем данные*/ + if(CloudServer.Gzip){ + Zlib.gzip(lList,CloudServer.getGzipDataFunc(lHeader,CloudServer.INDEX)); + } + /* если не поддерживаеться - отсылаем данные без сжатия*/ + else + CloudServer.sendResponse(lHeader,lList,CloudServer.INDEX); + } + else + { + console.log(pError); + CloudServer.sendResponse('OK',pError.toString()); + } +}; + +/* Функция генерирует функция считывания файла + * таким образом, что бы у нас было + * имя считываемого файла + * @pName - полное имя файла + */ +CloudServer.getReadFileFunc = function(pName){ +/* + * @pError - ошибка + * @pData - данные + * @pFromFile - прочитано с файла bool + */ + var lReadFile=function(pError,pData,pFromCache_b){ + if (!pError){ + console.log('file ' + pName + ' readed'); + + /* берём из кэша данные файла + * если их нет в кэше - + * сохраняем + */ + if(!pFromCache_b && CloudServer.Cache.isAllowed) + CloudServer.Cache.set(pName,pData); + /* если кэш есть + * сохраняем его в переменную + * которая до этого будет пустая + * по скольку мы будем вызывать этот метод + * сами, ведь файл уже вычитан + */ + + var lHeader=CloudServer.generateHeaders(pName,CloudServer.Gzip); + /* если браузер поддерживает gzip-сжатие - сжимаем данные*/ + if(CloudServer.Gzip &&!pFromCache_b){ + /* сжимаем содержимое */ + Zlib.gzip(pData,CloudServer.getGzipDataFunc(lHeader,pName)); + } + else{ + /* высылаем несжатые данные */ + CloudServer.sendResponse(lHeader,pData,pName); + } + } + else + { + console.log(pError.path); + if(pError.path!=='passwd.json') + { + console.log(pError); + CloudServer.sendResponse('OK',pError.toString()); + }else{ + CloudServer.sendResponse('OK','passwd.json'); + } + } + }; + return lReadFile; +}; + +/* Функция получает сжатые данные + * @pHeader - заголовок файла + */ +CloudServer.getGzipDataFunc=function(pHeader,pName){ + return function(error,pResult){ + if(!error){ + /* отправляем сжатые данные + * вместе с заголовком + */ + /* если установлена работа с кэшем + * сохраняем сжатые данные + */ + if(CloudServer.Cache.isAllowed){ + /* устанавливаем кєш */ + console.log(pName+' gziped'); + CloudServer.Cache.set(pName+'_gzip',pResult); + } + CloudServer.sendResponse(pHeader,pResult,pName); + } + else{ + console.log(error); + CloudServer.sendResponse(pHeader,error); + } + }; +}; +/* Функция высылает ответ серверу + * @pHead - заголовок + * @pData - данные + * @pName - имя отсылаемого файла + */ +CloudServer.sendResponse = function(pHead, pData,pName){ + /* если у нас есть указатель на responce + * для соответствующего файла - + * высылаем его + */ + var lResponse=CloudServer.Responses[pName]; + if(lResponse){ + lResponse.writeHead(200,pHead); + lResponse.end(pData); + console.log(pName+' sended'); + } +}; + +CloudServer.start(); \ No newline at end of file diff --git a/cloudcmd1/1/style.css b/cloudcmd1/1/style.css new file mode 100644 index 00000000..57136168 --- /dev/null +++ b/cloudcmd1/1/style.css @@ -0,0 +1,317 @@ +/* +@import url(//fonts.googleapis.com/css?family=Droid+Sans+Mono); +*/ + +/* Foundation Icons General Enclosed */ +@font-face { + font-family: 'FoundationIconsGeneralEnclosed'; + src: url('//dl.dropbox.com/u/78163899/mnemonia/fonts/foundation-icons-general-enclosed.woff') format('woff'); + font-weight: normal; + font-style: normal; + +} +/* символьный шрифт от гитхаба*/ +@font-face { + font-family: 'Octicons Regular'; + font-style: normal; + font-weight: normal; + src: local('Octicons Regular'), url('//dl.dropbox.com/u/78163899/mnemonia/fonts/octicons-regular-webfont.woff') format('woff'); +} + +@font-face { + font-family: 'Droid Sans Mono'; + font-style: normal; + font-weight: normal; + src: local('Droid Sans Mono'), local('DroidSansMono'), url('http://themes.googleusercontent.com/static/fonts/droidsansmono/v4/ns-m2xQYezAtqh7ai59hJUYuTAAIFFn5GTWtryCmBQ4.woff') format('woff'); +} + +body{ + font:16px "Droid Sans Mono"; +} + +.menu{ + font: 16px 'Octicons Regular'; + margin-bottom: 0; +} + +.path_icon{ + font-family:'FoundationIconsGeneralEnclosed'; + font-size:30px; + color: #46A4C3;/*#55BF3F; green*/ + text-shadow:black 0 2px 1px; + /* размер иконки и позиция на png-файле*/ + width: 15px; + height: 15px; + display: inline-block; + position: relative; + top: 3px; + left: -4px; +} +.path_icon:hover{ + /* + color:#45D827; + */ + cursor:pointer; +} +.path_icon:active{ + text-shadow:black 0 0 1px; + position: relative; + top: 4px; +} +.icon{ + font-family: 'Octicons Regular'; + font-size:16px; + width:16px; + height:16px; + display:inline-block; + margin-left:0.5%; +} +.error::before{ + content:'\f026'; + cursor:default; + color:rgb(222, 41, 41); + position: relative; + top: -3px; +} +.loading{ + background:url(/img/spinner.gif); + position:relative; + top:1px; +} +.error:hover{ + color:rgba(222, 41, 41, 0.81); +} +.refresh-icon{ + background:url(/img/panel_refresh.png) no-repeat; +} +.refresh-icon:active{ + /*background-position-y: -15px;*/ +background:url(/img/panel_refresh.png) 0 -15px no-repeat; +} +.clear-cache{ + background:url(/img/console_clear.png) -4px -4px no-repeat; + margin-right: 6px; + margin-left: 7px; +} +.clear-cache:active{ + /* + background-position-y: -25px; + */ + top:5px; +} + +.settings:before{ + content:'k'; +} +.links{ + color:red; + } + +.mini-icon { + float: left; + height: 16px; + left: -5px; + margin-left: 6px; + position: relative; + top: 2px; + width: 16px; + /* отступ перед картинкой + * для нормального отображения + * рамки + */ +} +/* freeupex */ +.directory{ + /*list-style-image*/ + background-image:url('/img/dir.png'); + background-repeat: no-repeat; + background-position: 0 0; +} +.text-file{ + /*list-style-image*/ + background-image:url('/img/txt.png'); + background-repeat: no-repeat; + background-position: 0 0; +} +#fm{ + height:90%; + overflow-y: scroll; +} +.fm_header{ + font-weight: bold; +} +#path{ + margin-left:1.5%; +} +#left{ + float:left; + width:90%; +} +/* фон файла, на котором курсор*/ +.current-file{ + border: 2px solid rgba(49, 123, 249, .40); +} +.selected-file{ + background-color: rgba(49, 123, 249, .40); + color:white; +} +#right{ + float:right; +} +.panel{ + display: table; + width:45%; +} +#keyspanel{ + text-align: center; +} +/* информация о файлах и папках*/ +.name{ + float: left; + width: 37%; +} +.size{ + float:left; + width:16%; + /* Ставим выравнивание, + * что бы размер был в + * одной ровной колонке + */ + text-align: right; + /* Ставим отступ, что бы + * size не налазил на uid + * (owner) + */ + margin-right: 27px; +} +.owner{ +} +.mode{ + float: right; + width: 25%; +} + +ul,li{list-style-type:none;} +button{ + width:10%; +} +a{ + text-decoration:none; +} +a:hover, a:active { cursor:pointer;outline: 0; color: #06e; } +a:focus { outline: thin dotted; } + +/* Если размер окна очень маленький + * располагаем имя и атрибуты файла + * друг-под-другом +*/ +/* responsive design */ +@media only screen and (max-width: 600px){ + #left{ + width:90% !important; + } + .panel >li{ + margin:10px; + } + /* если правая панель не помещаеться - прячем её */ + #right{ + display:none; + } + /* текущий файл под курсором */ +.current-file{ + background-color: rgba(49, 123, 249, .40); + color:white; + } + /* делаем иконки под курсом белыми*/ +.current-file > .mini-icon{ + color:white; + } +.current-file > .text-file::before{ + color:white; + } + +/* меняем иконки на шрифтовые*/ + .mini-icon { + font: 60px 'Octicons Regular'; + width: 40%; + height: 0; + margin-left: 0; + float: right; + position: relative; + top: -17px; + + color: rgba(246, 224, 124, 0.56); + } + .directory::before{ + content: '\f216'; + } + .text-file::before{ + color: rgba(26, 224, 124, 0.56); + content: '\f211'; + } + .text-file{ + background-image:none; + } + + + + /* убираем заголовок*/ + .fm_header{ + display:none; + } + .mode,.size,.owner{ + /* располагаем элементы + * один под другим + */ + display: table; + float: none; + width: 0; + + text-align: left; + } + /* выводим заголовки рядом с полями */ + .name::before{ + content: 'name:'; + font-weight: bold; + font-size: 13px; + } + .mode::before{ + content: 'mode:'; + font-weight: bold; + font-size: 13px; + } + .size::before{ + content: 'size:'; + font-weight: bold; + font-size: 13px; + } + .owner::before{ + content: 'owner:'; + font-weight: bold; + font-size: 13px; + } + + .name{ + float: none; + width:100%; + font-size: 18px; + } +} +@media only screen and (min-width: 601px) and (max-width: 767px){ + #left{ + width:90% !important; + } + #right{ + display:none; + } +} + +@media only screen and (min-width:767px) and (max-width: 1060px){ + #left{ + width:90% !important; + } + /* если правая панель не помещаеться - прячем её */ + #right{ + display:none; + } +} \ No newline at end of file diff --git a/cloudcmd1/1/test.sh b/cloudcmd1/1/test.sh new file mode 100644 index 00000000..6b68a51f --- /dev/null +++ b/cloudcmd1/1/test.sh @@ -0,0 +1,4 @@ +#!/bin/sh +npm i -g jshint +echo "jshint server.js client.js lib/cloudfunc.js" +jshint --config ./.jshintrc ./server.js ./client.js ./lib/cloudfunc.js \ No newline at end of file diff --git a/cloudcmd1/README.md b/cloudcmd1/README.md new file mode 100644 index 00000000..49cf0cba --- /dev/null +++ b/cloudcmd1/README.md @@ -0,0 +1,49 @@ +Cloud Commander [![Build Status](https://secure.travis-ci.org/coderaiser/cloudcmd.png?branch=master)](http://travis-ci.org/coderaiser/cloudcmd) +=============== +**Cloud Commander** - two-panels file manager, totally writed on js. +View [demo](http://demo-cloudcmd.cloudfoundry.com/ "demo"). + +Google PageSpeed Score : [100](https://developers.google.com/speed/pagespeed/insights#url=http_3A_2F_2Fdemo-cloudcmd.cloudfoundry.com_2F&mobile=false "score") (out of 100). + +Benefits +--------------- +- full browser compatibility *(ie6+,chrome,safari,opera,firefox)*; +- responsible design +- one full page loading, *and then just one-time json-dir-listings loading +(with refresh opportunity).* +- caching readed directories *to localStorage (for now) +(so if network will disconnected or something heppen with a signal, we +definitely will can work cached copy of directory listings)*; +- key binding +- disabled js support *(working in limited mode)*. +- automated minification *client js-files and onstart-reading Cloud manager files on server starting.* + +**Cloud Commander** uses all benefits of js, so if js is disabled, +we moves to *limited mode*. + +Limited-mode features: +--------------- +- only 1 panel available +- no keybinding +- no local caching +- full loading of all web page(with styles, js-scripts, html-page etc). + +Hot keys: +--------------- +In all modern web browsers (but not in IE, becouse he special) hot keys works. +There is a short list: +- Ctrl + r - reload dir content +- Alt + q - disable key bindings +- Alt + s - get all key bindings back +- up, down, enter - filesystem navigation + + +Additional modules: +--------------- +**Cloud Commander** not using additional modules for main functionality. +But for minification and optimization tricks optional can be +assingned (and installed) modules: +- [UglifyJS] (https://github.com/mishoo/UglifyJS) +- [clean-css] (https://github.com/GoalSmashers/clean-css) +- [html-minifier] (https://github.com/kangax/html-minifier) +- [css-b64-images] (https://github.com/Filirom1/css-base64-images) \ No newline at end of file diff --git a/cloudcmd1/client.js b/cloudcmd1/client.js new file mode 100644 index 00000000..6331b051 --- /dev/null +++ b/cloudcmd1/client.js @@ -0,0 +1,736 @@ +/* Функция которая возвратит обьект CloudCommander + * @window - обьект window + * @document - обьект document + * @CloudFunc - обьект содержащий общий функционал + * клиентский и серверный + */ +//var CloudCommander=(function(window,document){ + +//var document,window; + +var CloudCommander=(function(){ +"use strict"; + +/* если функции console.log нет - создаём заглушку */ + +/* +var console; +if(!window)window={console:{log:function(pParam){return pParam;}}}; +else if(window && !window.console){ + console={ + 'log':function(param){ + return param; + } + }; +}else console=window.console; +*/ +/* + window.jQuery || document.write(' + + \ No newline at end of file diff --git a/cloudcmd1/lib/README.md b/cloudcmd1/lib/README.md new file mode 100644 index 00000000..a741f80c --- /dev/null +++ b/cloudcmd1/lib/README.md @@ -0,0 +1,5 @@ +Cloud Commander Libraries +=============== +**Cloud Commander Libraries** - dir thet contains scripts, thet uses +on client and server side, and modules, wich is not necessary +for CloudCommander work, but they adds some sugor. \ No newline at end of file diff --git a/cloudcmd1/lib/client/keyBinding.js b/cloudcmd1/lib/client/keyBinding.js new file mode 100644 index 00000000..2416002e --- /dev/null +++ b/cloudcmd1/lib/client/keyBinding.js @@ -0,0 +1,248 @@ +var CloudCommander; +var CloudFunc; +CloudCommander.keyBinding=(function(){ + "use strict"; + var key_event=function(event){ + /* + * Делаем допущение что перезагружать Cloud Commander + * посетителям не придёться, в любом случае, параметр + * должен быть опциональным и должна быть возможность + * его отключить. В любом случае, кроме хакеров и + * разработчиков (при чём сомнительно, что хакерам + * это пригодиться), функция перезагрузки никому не + * нужна, поскольку загружать весь дополнительный + * контент снова (js,css) в готовой версии нет + * необходимости. + * + */ + //console.log(event.keyCode); + var lCurrentFile; + var lName; + /* если клавиши можно обрабатывать*/ + if(CloudCommander.keyBinded){ + /* если нажали таб: + * переносим курсор на + * правую панель, если + * мы были на левой и + * наоборот + */ + if(event.keyCode===9){ + console.log('Tab pressed'); + try{ + lCurrentFile=document.getElementsByClassName(CloudCommander.CURRENT_FILE)[0]; + }catch(error){console.log(error);} + } + /* навигация по таблице файлов*/ + /* если нажали клавишу вверх*/ + else if(event.keyCode===38){ + /* получаем выдленный файл*/ + lCurrentFile=document.getElementsByClassName(CloudCommander.CURRENT_FILE); + /* если ненайдены выделенные файлы - выходим*/ + if(lCurrentFile.length===0)return; + lCurrentFile=lCurrentFile[0]; + /* если это строка существет и + * если она не заголовок + * файловой таблицы + */ + if(lCurrentFile.previousSibling && + lCurrentFile.previousSibling.className!=='fm_header' ){ + /* убираем выделение с текущего элемента */ + lCurrentFile.className=''; + /* и выделяем предыдущую строку*/ + lCurrentFile.previousSibling.className=CloudCommander.CURRENT_FILE; + event.preventDefault(); + } + } + /* если нажали клавишу в низ*/ + else if(event.keyCode===40){ + /* получаем выдленный файл*/ + lCurrentFile=document.getElementsByClassName(CloudCommander.CURRENT_FILE); + /* если ненайдены выделенные файлы - выходим*/ + if(lCurrentFile.length===0)return; + lCurrentFile=lCurrentFile[0]; + /* если это не последняя строка */ + if(lCurrentFile.nextSibling){ + /* убираем с него выделение */ + lCurrentFile.className=''; + /* выделяем следующую строку*/ + lCurrentFile.nextSibling.className=CloudCommander.CURRENT_FILE; + event.preventDefault(); + } + } + /* если нажали клавишу page up или Home + * переходим к самому верхнему + * элементу + */ + else if(/*event.keyCode===33 ||*/ event.keyCode===36){ + lCurrentFile=document.getElementsByClassName(CloudCommander.CURRENT_FILE)[0]; + /* убираем выделение с текущего файла*/ + lCurrentFile.className=''; + /* получаем первый элемент*/ + lCurrentFile.parentElement.firstElementChild + /* пропускаем путь и заголовки столбиков*/ + .nextElementSibling.nextElementSibling + /* выделяем верхий файл */ + .className=CloudCommander.CURRENT_FILE; + } + /* если нажали клавишу page down или End + * выделяем последний элемент + */ + else if(/*event.keyCode===34 ||*/ event.keyCode===35){ + lCurrentFile=document.getElementsByClassName(CloudCommander.CURRENT_FILE)[0]; + /* снимаем выделение с текущего файла*/ + lCurrentFile.className=''; + /* выделяем самый нижний файл */ + lCurrentFile.parentElement.lastElementChild.className=CloudCommander.CURRENT_FILE; + } + /* если нажали Enter - открываем папку*/ + else if(event.keyCode===13){ + lCurrentFile=document.getElementsByClassName(CloudCommander.CURRENT_FILE); + /* если ненайдены выделенные файлы - выходим*/ + if(!lCurrentFile.length)return; + lCurrentFile=lCurrentFile[0]; + /* из него достаём спан с именем файла*/ + lName=lCurrentFile.getElementsByClassName('name'); + /* если нету (что вряд ли) - выходим*/ + if(!lName)return false; + /* достаём все ссылки*/ + var lATag=lName[0].getElementsByTagName('a'); + /* если нету - выходим */ + if(!lATag)return false; + /* получаем ссылку на каталог, + * что на уровень выше + */ + /* получаем имя каталога в котором находимся*/ + var lHref; + try{ + lHref=lCurrentFile.parentElement.getElementsByClassName('path')[0].innerText; + }catch(error){console.log('error');} + lHref=CloudFunc.removeLastSlash(lHref); + var lSubstr=lHref.substr(lHref,lHref.lastIndexOf('/')); + lHref=lHref.replace(lSubstr+'/',''); + + /* вызываем ajaxload привязанный через changelinks + * пробулем нажать на ссылку, если не получиться + * (opera, ie), вызываем событие onclick, + * которое пока не прописано у файлов + */ + + if(lCurrentFile.onclick)lCurrentFile.onclick(true); + else try{ + lATag[0].click(); + } + catch(error){ + console.log(error); + } + } + /* если нажали +r */ + else if(event.keyCode===82 && + event.ctrlKey){ + console.log('+r pressed'); + console.log('reloading page...'); + console.log('press +q to remove all key-handlers'); + + /* обновляем страницу, */ + /* Загружаем содержимое каталога + * при этом данные берём всегда из + * сервера, а не из кэша + * (обновляем кэш) + */ + /* Программно нажимаем на кнопку перезагрузки + * содержимого каталога + */ + var lRefreshIcon=document.getElementsByClassName(CloudFunc.REFRESHICON); + if(lRefreshIcon)lRefreshIcon=lRefreshIcon[0]; + if(lRefreshIcon){ + /* находим файл который сейчас выделен */ + lCurrentFile=document.getElementsByClassName(CloudCommander.CURRENT_FILE); + if(lCurrentFile.length>0)lCurrentFile=lCurrentFile[0]; + /* получаем название файла*/ + var lSelectedName=lCurrentFile.getElementsByTagName('a')[0].innerText; + /* если нашли элемент нажимаем него + * а если не можем - нажимаем на + * ссылку, на которую повешен eventHandler + * onclick + */ + if(lRefreshIcon.click)lRefreshIcon.parentElement.click(); + else lRefreshIcon.parentElement.onclick(); + + /* перебираем файлы левой панели + * в поисках подсвеченого файла + */ + var lLeft=document.getElementById('left'); + if(lLeft){ + /* перебираем все файлы в панели */ + var lLi=lLeft.getElementsByTagName('li'); + lCurrentFile.className=''; + /* начинаем с 2-ух, по скольку + * 0 - это путь + * 1 - это заголовок файловой таблицы + */ + for(var i=2;i+d чистим кэш */ + else if(event.keyCode===68 && + event.ctrlKey){ + console.log('+d pressed'); + console.log('clearing cache...'); + console.log('press +q to remove all key-handlers'); + + var lClearCache=document.getElementById('clear-cache'); + if(lClearCache && lClearCache.onclick)lClearCache.onclick(); + + event.preventDefault();//запрет на дальнейшее действие + } + /* если нажали +q + * убираем все обработчики + * нажатий клавиш + */ + else if(event.keyCode===81 && + event.altKey){ + //document.removeEventListener('keydown', key_event,false); + console.log('+q pressed'); + console.log('+r reload key-handerl - removed'); + console.log('+s clear cache key-handler - removed'); + console.log('press +s to to set them'); + + /* обработчик нажатий клавиш снят*/ + CloudCommander.keyBinded=false; + } + } + /* если нажали +s + * устанавливаем все обработчики + * нажатий клавиш + */ + else if(event.keyCode===83 && + event.altKey){ + /* + document.addEventListener('keydown', key_event,false); + */ + /* обрабатываем нажатия на клавиши*/ + CloudCommander.keyBinded=true; + + console.log('+s pressed'); + console.log('+r reload key-handerl - set'); + console.log('+s clear cache key-handler - set'); + console.log('press +q to remove them'); + } + + return false; + }; + /* добавляем обработчик клавишь */ + if(document.addEventListener) + document.addEventListener('keydown', key_event,false); + else document.onkeypress=key_event; + /* клавиши назначены*/ + CloudCommander.keyBinded=true; +}); \ No newline at end of file diff --git a/cloudcmd1/lib/cloudfunc.js b/cloudcmd1/lib/cloudfunc.js new file mode 100644 index 00000000..2c1c62b0 --- /dev/null +++ b/cloudcmd1/lib/cloudfunc.js @@ -0,0 +1,513 @@ +"use strict"; +/* Модуль, содержащий функции, которые будут работать + * и на клиенте и на сервере + * + * Правила названий: + * varName - имя функции + * lVarName - имя локальной переменной + * pVarName - имя параметра + * fVarName - имя функции созданной внутри функции + * VARNAME - имя константы + * + * Типы переменных: + * varNameS - строка + * varNameN - число + * varNameO - обьект + * varNameM - массив + */ + +var CloudFunc={ + /* Путь с которым мы сейчас работаем */ + Path :'', + /* КОНСТАНТЫ (общие для клиента и сервера)*/ + /* название программы */ + NAME :'Cloud Commander', + /* если в ссылке будет эта строка - + * в браузере js отключен + */ + NOJS : '/no-js', + FS : '/c/f/s', + /* название css-класа кнопки обновления файловой структуры*/ + REFRESHICON : 'refresh-icon', + /* id панелей с файлами */ + LEFTPANEL : 'left', + RIGHTPANEL : 'right' + /* name of direcotory with libs */ +}; + +/* + * Функция убирает последний слеш, + * если он - последний символ строки + */ +CloudFunc.removeLastSlash = function(pPath){ + if(typeof pPath==='string') + return (pPath.lastIndexOf('/')===pPath.length-1)? + pPath.substr(pPath, pPath.length-1):pPath; + else return pPath; +}; +/* + * Функция меняет код символа пробела на пробел + * в переданной строке + * @pPath - строка + */ +CloudFunc.replaceSpaces = function(pPath){ + if(pPath.indexOf('%20')>0){ + do{ + pPath=pPath.replace('%20',' '); + }while(pPath.indexOf('%20')>0); + } + return pPath; +}; + +/* Функция возвращает заголовок веб страницы */ +CloudFunc.setTitle = function(){ + + return CloudFunc.Path===''?CloudFunc.NAME: + CloudFunc.Path + + ' - ' + + CloudFunc.NAME; +}; +/* Функция переводит права из цыфрового вида в символьный + * @pPerm_s - строка с правами доступа + * к файлу в 8-миричной системе + */ +CloudFunc.convertPermissionsToSymbolic= function(pPerm_s){ + /* + S_IRUSR 0000400 protection: readable by owner + S_IWUSR 0000200 writable by owner + S_IXUSR 0000100 executable by owner + S_IRGRP 0000040 readable by group + S_IWGRP 0000020 writable by group + S_IXGRP 0000010 executable by group + S_IROTH 0000004 readable by all + S_IWOTH 0000002 writable by all + S_IXOTH 0000001 executable by all + */ + if(pPerm_s===undefined) return; + + /* тип файла */ + var lType=pPerm_s.charAt(0); + + switch (lType-0) { + case 1: /* обычный файл */ + lType='-'; + break; + case 2: /* байт-ориентированное (символьное) устройство*/ + lType='c'; + break; + case 4: /* каталог */ + lType='d'; + break; + default: + lType='-'; + } + + /* оставляем последние 3 символа*/ + pPerm_s=pPerm_s.length>5?pPerm_s.substr(3):pPerm_s.substr(2); + + /* Рекомендации гугла советуют вместо string[3] + * использовать string.charAt(3) + */ +/* + http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml?showone=Standards_features#Standards_features + + Always preferred over non-standards featuresFor + maximum portability and compatibility, always + prefer standards features over non-standards + features (e.g., string.charAt(3) over string[3] + and element access with DOM functions instead + of using an application-specific shorthand). +*/ + /* Переводим в двоичную систему */ + var lOwner=(pPerm_s[0]-0).toString(2); + var lGroup=(pPerm_s[1]-0).toString(2); + var lAll =(pPerm_s[2]-0).toString(2); + /* + console.log(lOwner+' '+lGroup+' '+lAll); + */ + /* переводим в символьную систему*/ + var lPermissions=//lType+' '+ + (lOwner[0]-0>0?'r':'-')+ + (lOwner[1]-0>0?'w':'-')+ + (lOwner[2]-0>0?'x':'-')+ + ' ' + + (lGroup[0]-0>0?'r':'-')+ + (lGroup[1]-0>0?'w':'-')+ + (lGroup[2]-0>0?'x':'-')+ + ' ' + + (lAll[0]-0>0?'r':'-')+ + (lAll[1]-0>0?'w':'-')+ + (lAll[2]-0>0?'x':'-'); + /* + console.log(lPermissions); + */ + return lPermissions; +}; + +/* Функция конвертирует права доступа к файлам из символьного вида + * в цыфровой + */ +CloudFunc.convertPermissionsToNumberic= function(pPerm_s){ + /* если передана правильная строка, конвертированная + * функциец convertPermissionsToSymbolic + */ + if(!pPerm_s || pPerm_s.length!==11)return pPerm_s; + + var lOwner= (pPerm_s[0]==='r'?4:0) + + (pPerm_s[1]==='w'?2:0) + + (pPerm_s[2]==='x'?1:0); + var lGroup= (pPerm_s[4]==='r'?4:0) + + (pPerm_s[5]==='w'?2:0) + + (pPerm_s[6]==='x'?1:0); + var lAll = (pPerm_s[8]==='r'?4:0) + + (pPerm_s[9]==='w'?2:0) + + (pPerm_s[10]==='x'?1:0); + /* добавляем 2 цыфры до 5 */ + return '00'+lOwner+lGroup+lAll; +}; +/* Функция получает короткие размеры + * конвертируя байт в килобайты, мегабойты, + * гигайбайты и терабайты + * @pSize - размер в байтах + */ +CloudFunc.getShortedSize=function(pSize){ + /* Константі размеров, что используются + * внутри функции + */ + var l1BMAX=1024; + var l1KBMAX=1048576; + var l1MBMAX=1073741824; + var l1GBMAX=1099511627776; + var l1TBMAX=1125899906842624; + + var lShorted; + + if(pSize2){ + if(folders[0].lastIndexOf('/')===folders[0].length) + LPrevDir=folders[1]; + else LPrevDir=folders[2]; + }else LPrevDir='/'; + */ + /* ################################### */ + + /* Формируем ссылки на каждый каталог в пути */ + var lHref=''; + var lHrefEnd=''; + + var lHtmlPath; + /* путь в ссылке, который говорит + * что js отключен + */ + var lNoJS_s=CloudFunc.NOJS; + var lFS_s=CloudFunc.FS; + /* корневой каталог */ + lHtmlPath=lHref+lFS_s+lNoJS_s+lTitle+'"/"'+_l+'/'+lHrefEnd; + for(i=folders.length-1;i>0;i--) + { + var lUrl=folders[i]; + var lShortName=lUrl.replace(lUrl.substr(lUrl,lUrl.lastIndexOf('/')+1),''); + if(i!==1) + { + lHtmlPath+=lHref+lFS_s+lNoJS_s+lUrl+lTitle+lUrl+_l+lShortName+lHrefEnd+'/'; + } + else + lHtmlPath+=lShortName+'/'; + } + /* *** */ + return lHtmlPath; +}; + +/* + * Функция ищет в имени файла расширение + * и если находит возвращает true + * @pName - получает имя файла + * @pExt - расширение + */ +CloudFunc.checkExtension=function(pName,pExt) +{ + /* если длина имени больше + * длинны расширения - + * имеет смысл продолжать + */ + if(pName.length>pExt.length){ + var lLength=pName.length; /* длина имени*/ + var lExtNum=pName.lastIndexOf(pExt);/* последнее вхождение расширения*/ + var lExtSub=lLength-lExtNum; /* длина расширения*/ + /* если pExt - расширение pName */ + if(lExtSub===pExt.length) + return true; + else + return false; + } + else return false; +}; + +/* + * Функция формирует заголовки столбиков + * @pFileTableTitles - массив названий столбиков + */ +CloudFunc._getFileTableHeader=function(pFileTableTitles) +{ + var lHeader='
  • '; + lHeader+=''; + for(var i=0;i'+ + lStr+ + ''; + } + lHeader+='
  • '; + + return lHeader; +}; + +/* + * Функция строит таблицу файлв из JSON-информации о файлах + * @pJSON - информация о файлах + * @pKeyBinded - если клавиши назначены, выделяем верхний файл + * [{path:'путь',size:'dir'}, + * {name:'имя',size:'размер',mode:'права доступа'}] + */ +CloudFunc.buildFromJSON=function(pJSON,pKeyBinded) +{ + var files; + /* + * если пропарсить стандартными + * функциями нельзя - + * пробуем eval, + */ + /* + * Если мы на клиенте и нет JSON - + * через eval парсим. + * Если-же мы на сервере, + * или на клиенте всё есть + * парсим стандарным методом + */ + + /* По скольку мы прописали заголовок application/json + * нет необходимости его конвертировать, + * но она есть, если мы вытягиваем данные из + * localStorage + */ + /* + if(typeof pJSON==='string'){ + if(window && !window.JSON){ + try{ + files=eval('('+pJSON+')'); + }catch(err){ + console.log(err); + } + } + else files=JSON.parse(pJSON); + }else + */ + files=pJSON; + /* сохраняем путь каталога в котором мы сейчас находимся*/ + var lPath=files[0].path; + + /* сохраняем путь */ + CloudFunc.Path=lPath; + + /* + * Строим путь каталога в котором мы находимся + * со всеми подкаталогами + */ + var lHtmlPath=CloudFunc._getDirPath(lPath); + + /* Убираем последний слэш + * с пути для кнопки обновить страницу + * если он есть + */ + var lRefreshPath=CloudFunc.removeLastSlash(lPath); + + /* путь в ссылке, который говорит + * что js отключен + */ + var lNoJS_s=CloudFunc.NOJS; + var lFS_s=CloudFunc.FS; + + var lFileTable='
  • '+ + ''+ + ''+ + '' + + ''+ + ''+ + ''+lHtmlPath+''+ + '
  • '; + + var fileTableTitles=['name','size','owner','mode']; + lFileTable+=CloudFunc._getFileTableHeader(fileTableTitles); + /* Если мы не в корне */ + if(lPath!=='/'){ + /* ссылка на верхний каталог*/ + var lDotDot; + /* убираем последний слеш и каталог в котором мы сейчас находимся*/ + lDotDot=lPath.substr(lPath,lPath.lastIndexOf('/')); + lDotDot=lDotDot.substr(lDotDot,lDotDot.lastIndexOf('/')); + /* Если предыдущий каталог корневой */ + if(lDotDot==='')lDotDot='/'; + + /* Сохраняем путь к каталогу верхнего уровня*/ + lFileTable += '
  • '+ + '' + + '' + + '' + + ''+".." + + '' + + '<dir>'+ + '.' + + '' + + '
  • '; + } + var lLength=files.length; + + for(var i=1;i'; + lFileTable +=''; + lFileTable +='' + + '16? + ' title="'+files[i].name+'">' + + files[i].name.substr( + files[i].name,16)+ + '..':'>'+files[i].name) + + "" + + ''; + /* если папка - не выводим размер */ + lFileTable +='' + + (files[i].size==='dir'? + '<dir>': + /* если это файл - получаем + * короткий размер + */ + CloudFunc.getShortedSize( + files[i].size)); + lFileTable +='' + + '' + + (!files[i].uid?'root':files[i].uid) + + '' + + '' + + /* конвертируем названия разрешений + * из числового формата в буквенный + * при этом корневой каталог не трогаем + * по скольку в нём и так всё уже + * установлено еще на сервере + */ + (//lPath==='/'?files[i].mode: + CloudFunc.convertPermissionsToSymbolic(files[i].mode)) + + ''; + lFileTable +=''; + } + + /* если клавиши назначены и + * мы в корневом каталоге и + * верхний файл еще не выделен - + * выделяем верхний файл + */ + if(pKeyBinded && lPath==='/'&& + lFileTable.indexOf('
  • ')<0){ + lFileTable=lFileTable.replace('
  • ','
  • '); + } + + + + return lFileTable; +}; + +/* + * Если мы на стороне сервера - + * прописываем экспортируемые функции + */ +try{ + if(exports){ + /* экспортируемые функции */ + exports.checkExtension = CloudFunc.checkExtension; + exports.buildFromJSON = CloudFunc.buildFromJSON; + exports.replaceSpaces = CloudFunc.replaceSpaces; + exports.setTitle = CloudFunc.setTitle; + exports.convertPermissions = CloudFunc.convertPermissions; + exports.getUserUIDsAndNames = CloudFunc.getUserUIDsAndNames; + + /* константы*/ + exports.Name = CloudFunc.NAME; + exports.NOJS = CloudFunc.NOJS; + exports.FS =CloudFunc.FS; + + console.log('cloudfunc.js loaded...'); + } +}catch(err){ + /* если мы на клиенте */ +} \ No newline at end of file diff --git a/cloudcmd1/lib/server/minify.js b/cloudcmd1/lib/server/minify.js new file mode 100644 index 00000000..556fd119 --- /dev/null +++ b/cloudcmd1/lib/server/minify.js @@ -0,0 +1,274 @@ +/* Модуль сжатия js-скриптов и css*/ + +/* функция сжимает js-скрипты + * и сохраняет их с именем .min.js + */ + +var fs = require('fs'); + +exports.jsScripts=function jsScripts(){ + 'use strict'; + + /* подключаем модуль uglify-js + * если его нет - дальнейшая + * работа функции не имеет смысла + */ + try{ + var jsp = require("uglify-js").parser; + var pro = require("uglify-js").uglify; + }catch(error){ + console.log('can\'n load uglify-js\n' + + 'to use js-minification you need to install uglify-js\n' + + 'npm install uglify-js\n' + + 'https://github.com/mishoo/UglifyJS'); + return false; + } + /* Константы */ + var CLIENT_JS='client.js'; + var CLOUDFUNC_JS='lib/cloudfunc.js'; + var CLIENT_KEYBINDING_JS='lib/client/keyBinding.js'; + + var dataReaded_f=function(pFileName, pData){ + console.log('file ' + pFileName + ' readed'); + + /*********************************/ + /* сжимаем код через uglify-js */ + var uglify_js=function(pDdata){ + var orig_code = pDdata.toString(); + var ast = jsp.parse(orig_code); // parse code and get the initial AST + ast = pro.ast_mangle(ast); // get a new AST with mangled names + ast = pro.ast_squeeze(ast); // get an AST with compression optimizations + var result_code = pro.gen_code(ast); // compressed code here + return result_code; + }; + /*********************************/ + var final_code=uglify_js(pData); + + var minFileName=pFileName.replace('.js','.min.js'); + /* если мы сжимаем client.js - + * меняем строку cloudfunc.js на + * cloudfunc.min.js и выводим сообщение + * + * меняем строку keyBinding.js на + * keyBinding.min.js + * если другой файл - ничего не деалем + */ + if(pFileName===CLIENT_JS) + console.log('file name of ' + + CLOUDFUNC_JS + + ' in ' + + CLIENT_JS + + ' changed. size:', + (final_code=final_code + .replace('cloudfunc.js','cloudfunc.min.js') + .replace('keyBinding.js','keyBinding.min.js')).length); + + /* записываем сжатый js-скрипт*/ + fs.writeFile(minFileName, final_code, fileWrited(minFileName)); + }; + console.log('reading file ' + CLIENT_JS+'...'); + fs.readFile(CLIENT_JS,fileReaded(CLIENT_JS,dataReaded_f)); + + console.log('reading file ' + CLOUDFUNC_JS+'...'); + fs.readFile(CLOUDFUNC_JS,fileReaded(CLOUDFUNC_JS,dataReaded_f)); + + console.log('reading file ' + CLIENT_KEYBINDING_JS+'...'); + fs.readFile(CLIENT_KEYBINDING_JS, fileReaded(CLIENT_KEYBINDING_JS,dataReaded_f)); + + + return true; +}; + +/* функция сжимает css-стили + * и сохраняет их с именем .min.css + * @pImgConvertToBase64_b - булевый признак, + * который отвечает за то, что быконвертировать + * картинки в base64 и поместить в выходной css файл + */ +exports.cssStyles=function cssStyles(pImgConvertToBase64_b){ + 'use strict'; + + /* connecting cleanCSS, + * if we can't find it - + * return false + */ + var cleanCSS; + try{ + cleanCSS = require('clean-css'); + }catch(error){ + console.log('can\'n load clean-css \n' + + 'to use css-minification you need to install clean-css \n' + + 'npm install clean-css\n' + + 'https://github.com/GoalSmashers/clean-css'); + return false; + } + + /* Константы */ + var STYLE_CSS='style.css'; + var RESET_CSS='reset.css'; + + var lAllStyle=''; + var lResetCssDone=false; + var lStyleCssDone=false; + var dataReaded_f=function(pFileName, pData){ + console.log('file ' + pFileName + ' readed'); + /*********************************/ + /* сжимаем код через clean-css */ + var clean_css=function(pData){ + /* Сохраняем весь стиль в одну переменную*/ + return cleanCSS.process(pData); + }; + /*********************************/ + var final_code=clean_css(pData); + + lAllStyle+=final_code; + + var minFileName=pFileName.replace('.css','.min.css'); + + if(pFileName===STYLE_CSS)lStyleCssDone=true; + if(pFileName===RESET_CSS)lResetCssDone=true; + /* if all files writed we + * save all minimized css + * to one file all.min.css + */ + /* если включена конвертация картинок в base64 + * вызываем её + */ + if(lStyleCssDone && lResetCssDone) + if(pImgConvertToBase64_b) + base64_images(lAllStyle); + else + fs.writeFile('all.min.css', lAllStyle, fileWrited('all.min.css')); + + /* записываем сжатый css файл*/ + else fs.writeFile(minFileName, final_code, fileWrited(minFileName)); + }; + + console.log('reading file ' + STYLE_CSS+'...'); + fs.readFile(STYLE_CSS,fileReaded(STYLE_CSS,dataReaded_f)); + + console.log('reading file ' + RESET_CSS+'...'); + fs.readFile(RESET_CSS,fileReaded(RESET_CSS,dataReaded_f)); + + return true; +}; + +/* функция сжимает css-стили + * и сохраняет их с именем .min.css + */ +exports.html=function(){ + 'use strict'; + + /* connecting cleanCSS, + * if we can't find it - + * return false + */ + var htmlMinifier; + try{ + htmlMinifier = require('html-minifier'); + }catch(error){ + console.log('can\'n load html-minifier \n' + + 'to use html-minification you need to install html-minifier\n' + + 'npm install html-minifier\n' + + 'https://github.com/kangax/html-minifier'); + return false; + } + + /* Константы */ + var INDEX_HTML='index.html'; + + var dataReaded_f=function(pFileName, pData){ + console.log('file ' + pFileName + ' readed'); + /*********************************/ + /* сжимаем код через clean-css */ + var html_minify=function(pData){ + /* Сохраняем весь стиль в одну переменную*/ + + var lOptions={ + removeComments: true, + removeCommentsFromCDATA: true, + removeCDATASectionsFromCDATA: true, + collapseWhitespace: true, + collapseBooleanAttributes: true, + removeAttributeQuotes: true, + removeRedundantAttributes: true, + useShortDoctype: true, + removeEmptyAttributes: true, + /* оставляем, поскольку у нас + * в элемент fm генерируеться + * таблица файлов + */ + removeEmptyElements: false, + removeOptionalTags: true, + removeScriptTypeAttributes: true, + removeStyleLinkTypeAttributes: true + }; + + + return htmlMinifier.minify(pData,lOptions); + }; + /*********************************/ + var final_code=html_minify(pData); + + var minFileName=pFileName.replace('.html','.min.html'); + + /* записываем сжатый html файл*/ + fs.writeFile(minFileName, final_code, fileWrited(minFileName)); + }; + + console.log('reading file ' + INDEX_HTML+'...'); + fs.readFile(INDEX_HTML,fileReaded(INDEX_HTML,dataReaded_f)); + + return true; +}; + +/* функция переводит картинки в base64 и записывает в css-файл*/ +function base64_images(pFileContent_s){ + 'use strict'; + var b64img; + try{ + b64img = require('css-b64-images'); + }catch(error){ + console.log('can\'n load clean-css \n' + + 'to use images to base64 convertation you need to install css-base64-images \n' + + 'npm install -g css-b64-images\n' + + 'https://github.com/Filirom1/css-base64-images'); + return false; + } + b64img.fromString(pFileContent_s, '.','', function(err, css){ + fs.writeFile('all.min.css', css, fileWrited('all.min.css')); + }); +} + +/* Функция создаёт асинхроную версию + * для чтения файла + * @pFileName - имя считываемого файла + */ +function fileReaded(pFileName,pCompressFunc){ + "use strict"; + return function(pError,pData){ + /* функция в которую мы попадаем, + * если данные считались + * + * если ошибка - показываем её + * иначе если переданная функция - + * функция запускаем её + */ + if(!pError) + if (pCompressFunc && typeof pCompressFunc==="function") + pCompressFunc(pFileName,pData.toString()); + else console.log(pError); + }; +} + +/* + * Функция вызываеться после записи файла + * и выводит ошибку или сообщает, + * что файл успешно записан + */ +function fileWrited(pFileName){ + "use strict"; + return function(error){ + console.log(error?error:('file '+pFileName+' writed...')); + }; +} \ No newline at end of file diff --git a/cloudcmd1/node_modules/.bin/jitsu b/cloudcmd1/node_modules/.bin/jitsu new file mode 120000 index 00000000..ab860a6f --- /dev/null +++ b/cloudcmd1/node_modules/.bin/jitsu @@ -0,0 +1 @@ +../jitsu/bin/jitsu \ No newline at end of file diff --git a/cloudcmd1/node_modules/.bin/nodester b/cloudcmd1/node_modules/.bin/nodester new file mode 120000 index 00000000..aa4a5eb1 --- /dev/null +++ b/cloudcmd1/node_modules/.bin/nodester @@ -0,0 +1 @@ +../nodester-cli/bin/nodester.js \ No newline at end of file diff --git a/cloudcmd1/node_modules/jitsu b/cloudcmd1/node_modules/jitsu new file mode 120000 index 00000000..d5540629 --- /dev/null +++ b/cloudcmd1/node_modules/jitsu @@ -0,0 +1 @@ +../../local/lib/node_modules/jitsu \ No newline at end of file diff --git a/cloudcmd1/node_modules/nodester-cli b/cloudcmd1/node_modules/nodester-cli new file mode 120000 index 00000000..da254801 --- /dev/null +++ b/cloudcmd1/node_modules/nodester-cli @@ -0,0 +1 @@ +../../local/lib/node_modules/nodester-cli \ No newline at end of file diff --git a/cloudcmd1/package.json b/cloudcmd1/package.json new file mode 100644 index 00000000..4bcf5c47 --- /dev/null +++ b/cloudcmd1/package.json @@ -0,0 +1,16 @@ +{ + "name": "cloudcmd1", + "version": "0.0.1-10", + "scripts": { + "start": "server.js" + }, + "engines": { + "node": "0.6.x" + }, + "subdomain": "cloudcmd1", + "dependencies": { + "uglify-js": "*", + "html-minifier": "*", + "clean-css": "*" + } +} diff --git a/cloudcmd1/package2.json b/cloudcmd1/package2.json new file mode 100644 index 00000000..f2d59387 --- /dev/null +++ b/cloudcmd1/package2.json @@ -0,0 +1,12 @@ +{ + "name": "cloudcmd", + "version": "0.0.1-3", + "scripts": { + + "start": "server.js" + }, + "engines": { + "node": "0.6.x" + }, + "subdomain": "cloudcmd" +} diff --git a/cloudcmd1/reset.css b/cloudcmd1/reset.css new file mode 100644 index 00000000..a24c865b --- /dev/null +++ b/cloudcmd1/reset.css @@ -0,0 +1,100 @@ +/* ============================================================================= + HTML5 display definitions + ========================================================================== */ + +/* +article, aside, details, figcaption, figure, footer, header, hgroup, nav, section { display: block; } +audio, canvas, video { display: inline-block; *display: inline; *zoom: 1; } +audio:not([controls]) { display: none; } +[hidden] { display: none; } +*/ + +/* ============================================================================= + Base + ========================================================================== */ + +/* + * 1. Correct text resizing oddly in IE6/7 when body font-size is set using em units + * 2. Prevent iOS text size adjust on device orientation change, without disabling user zoom: h5bp.com/g + */ + +html { font-size: 100%; -webkit-text-size-adjust: 100%; -ms-text-size-adjust: 100%; font-family: sans-serif; color: #222;} +body { margin: 0; font-size: 1em; line-height: 1.4; } + +/* + * Remove text-shadow in selection highlight: h5bp.com/i + * These selection declarations have to be separate + * Also: hot pink! (or customize the background color to match your design) + */ +/* +::-moz-selection { background: #fe57a1; color: #fff; text-shadow: none; } + ::selection { background: #fe57a1; color: #fff; text-shadow: none; } +*/ +::selection { text-shadow: none; opacity: 0;} + + +/* ============================================================================= + Links + ========================================================================== */ + +a {text-decoration:none; color: #00e; } +a:visited { color: #551a8b; } +a:hover { color: #06e; } +a:focus { outline: thin dotted; } + +/* Improve readability when focused and hovered in all browsers: h5bp.com/h */ +a:hover, a:active { outline: 0; } + +ul{ margin: 1em 0; padding: 0 0 0 40px; } + +/* + * 1. Display hand cursor for clickable form elements + * 2. Allow styling of clickable form elements in iOS + * 3. Correct inner spacing displayed oddly in IE7 (doesn't effect IE6) + */ + + +/* ============================================================================= + Chrome Frame Prompt + ========================================================================== */ + +.chromeframe { margin: 0.2em 0; background: #ccc; color: black; padding: 0.2em 0; } + + +/* ==|== non-semantic helper classes ======================================== + Please define your styles before this section. + ========================================================================== */ + +/* For image replacement */ +.ir { display: block; border: 0; text-indent: -999em; overflow: hidden; background-color: transparent; background-repeat: no-repeat; text-align: left; direction: ltr; *line-height: 0; } +.ir br { display: none; } + +/* Hide from both screenreaders and browsers: h5bp.com/u */ +.hidden { display: none !important; visibility: hidden; } + +/* Hide only visually, but have it available for screenreaders: h5bp.com/v */ +.visuallyhidden { border: 0; clip: rect(0 0 0 0); height: 1px; margin: -1px; overflow: hidden; padding: 0; position: absolute; width: 1px; } + +/* Extends the .visuallyhidden class to allow the element to be focusable when navigated to via the keyboard: h5bp.com/p */ +.visuallyhidden.focusable:active, .visuallyhidden.focusable:focus { clip: auto; height: auto; margin: 0; overflow: visible; position: static; width: auto; } + +/* Hide visually and from screenreaders, but maintain layout */ +.invisible { visibility: hidden; } + +/* Contain floats: h5bp.com/q */ +.clearfix:before, .clearfix:after { content: ""; display: table; } +.clearfix:after { clear: both; } +.clearfix { *zoom: 1; } + +/* ==|== print styles ======================================================= + Print styles. + Inlined to avoid required HTTP connection: h5bp.com/r + ========================================================================== */ + +@media print { + * { background: transparent !important; color: black !important; box-shadow:none !important; text-shadow: none !important; filter:none !important; -ms-filter: none !important; } /* Black prints faster: h5bp.com/s */ + a, a:visited { text-decoration: underline; } + a[href]:after { content: " (" attr(href) ")"; } + .ir a:after, a[href^="javascript:"]:after, a[href^="#"]:after { content: ""; } /* Don't show links for images, or javascript/internal links */ + @page { margin: 0.5cm; } +} \ No newline at end of file diff --git a/cloudcmd1/server.js b/cloudcmd1/server.js new file mode 100644 index 00000000..2839b1ef --- /dev/null +++ b/cloudcmd1/server.js @@ -0,0 +1,635 @@ +"use strict"; + +/* Обьект содержащий все функции и переменные + * серверной части Cloud Commander'а + */ +var CloudServer={ + /* функция, которая генерирует заголовки + * файлов, отправляемые сервером клиенту + */ + generateHeaders :function(){}, + /* функция высылает + * данные клиенту + */ + sendResponse :function(){}, + /* Структура содержащая функции, + * и переменные, в которых + * говориться о поддерживаемых + * браузером технологиях + */ + BrowserSuport :{}, + /* Обьект для работы с кэшем */ + Cashe :{}, + /* Обьект через который + * выполняеться сжатие + * скриптов и стилей + */ + Minify :{}, + /* Асоциативный масив обьектов для + * работы с ответами сервера + * высылаемыми на запрос о файле и + * хранащий информацию в виде + * Responces[name]=responce; + */ + Responses :{}, + + /* ПЕРЕМЕННЫЕ */ + /* Поддержка браузером JS*/ + NoJS :true, + /* Поддержка gzip-сжатия + * браузером + */ + Gzip :undefined, + + /* КОНСТАНТЫ */ + /* index.html */ + INDEX :'index.html', + /* name of direcotory with libs */ + LIBDIR :'./lib', + LIBDIRSERVER :'./lib/server' +}; + +/* + * Обьект для работы с кэшем + * аналог клиентского обьекта + * с тем отличием, что в нём + * будут храниться серверные + * данные, такие как файлы + * отдаваемые клиенту + * (файлы проэкта по большому + * счёту, для ускорения + * первичной загрузки) + */ +CloudServer.Cache={ + _allowed :true, /* приватный переключатель возможности работы с кэшем */ + /* данные в которых храняться файлы + * в формате <поле> : <значение> + * _data[name]=pData; + * одному имени соответствуют + * одни данные + */ + _data :{}, + + /* функция говорит можно ли работать с кэшем */ + isAllowed :(function(){ + return CloudServer.Cache._allowed; + }), + /* функция устанавливает возможность работать с кэшем */ + setAllowed :(function(pAllowed){ + CloudServer.Cache._allowed=pAllowed; + }), + /* Если доступен кэш + * сохраняем в него данные + */ + set :(function(pName, pData){ + if(CloudServer.Cache._allowed && pName && pData){ + CloudServer.Cache._data[pName]=pData; + } + }), + /* Если доступен Cache принимаем из него данные*/ + get :(function(pName){ + if(CloudServer.Cache._allowed && pName){ + return CloudServer.Cache._data[pName]; + } + else return null; + }), + + /* Функция очищает кэш*/ + clear :(function(){ + if(CloudServer.Cache._allowed){ + CloudServer.Cache._data={}; + } + }) +}; + +/* Обьект для сжатия скриптов и стилей + * по умолчанию - сжимаються + */ +CloudServer.Minify={ + /* приватный переключатель минимизации */ + _allowed :{css:true,js:true,html:true, img: true}, + + /* функция разрешает или + * запрещает минимизировать + * css/js/html + * @pAllowed: - структура, в которой + * передаються параметры + * минификации, вида + * {js:true,css:true,html:false; img:true} + * img отвечает за перевод картинок в base64 + * и сохранение их в css-файл + */ + setAllowed :(function(pAllowed){ + if(pAllowed){ + this._allowed.css=pAllowed.css; + this._allowed.js=pAllowed.js; + this._allowed.html=pAllowed.html; + this._allowed.img=pAllowed.img; + } + }), + + /* + * Функция минимизирует css/js/html + * если установлены параметры минимизации + */ + doit :(function(){ + if(this._allowed.css || + this._allowed.js || + this._allowed.html){ + var lMinify = require(CloudServer.LIBDIRSERVER+'/minify'); + + this.done.js=this._allowed.js?lMinify.jsScripts():false; + this.done.html=this._allowed.html?lMinify.html():false; + this.done.css=this._allowed.css?lMinify.cssStyles(this._allowed.img):false; + } + }), + /* свойство показывающее случилась ли ошибка*/ + done:{js: false,css: false, html:false} +}; + + +var LeftDir='/'; +var RightDir=LeftDir; +/* + var Path = require('path'); +*/ /* модуль для работы с путями*/ + +var Fs = require('fs'); /* модуль для работы с файловой системой*/ + +var Zlib; +/* node v0.4 not contains zlib + */ +try{ + Zlib = require('zlib'); /* модуль для сжатия данных gzip-ом*/ +}catch(error){ + Zlib=undefined; + console.log('to use gzip-commpression' + + 'you should install zlib module\n' + + 'npm install zlib'); +} +var CloudFunc = require(CloudServer.LIBDIR + + (CloudServer.Minify.done.js?/* если стоит минификация*/ + '/cloudfunc.min':/* добавляем сжатый - иначе обычный */ + '/cloudfunc')); /* модуль с функциями */ +/* конструктор*/ +CloudServer.init=(function(){ + /* Переменная в которой храниться кэш*/ + CloudServer.Cache.setAllowed(true); + /* Change default parameters of + * js/css/html minification + */ + CloudServer.Minify.setAllowed({ + js:true, + css:true, + html:true, + img:true + }); + /* Если нужно минимизируем скрипты */ + CloudServer.Minify.doit(); +}); + + +/* создаём сервер на порту 31337*/ +CloudServer.start=function() +{ + CloudServer.init(); + + var http = require('http'); + http.createServer(CloudServer._controller).listen(process.env.PORT || + process.env.VCAP_APP_PORT /* cloudfoundry */ || + 31337, + '0.0.0.0' || '127.0.0.1'); + console.log('Cloud Commander server running at http://127.0.0.1:'+ + (process.env.PORT===undefined?31337:process.env.PORT)); +}; + + +/* Функция создаёт заголовки файлов + * в зависимости от расширения файла + * перед отправкой их клиенту + * @pName - имя файла + * @pGzip - данные сжаты gzip'ом + */ +CloudServer.generateHeaders = function(pName, pGzip){ + var lType=''; + /* высылаем заголовок в зависимости от типа файла */ + /* если расширение у файла css - + * загружаем стили + */ + if(CloudFunc.checkExtension(pName,'css')) + lType='text/css'; + /* загружаем js */ + else if(CloudFunc.checkExtension(pName,'js')) + lType='text/javascript'; + /* загружаем картинки*/ + else if(CloudFunc.checkExtension(pName,'png')) + lType='image/png'; + /* загружаем json*/ + else if(CloudFunc.checkExtension(pName,'json')) + lType='application/json'; + else if(CloudFunc.checkExtension(pName,'html')) + lType='text/html'; + else if(CloudFunc.checkExtension(pName,'appcache')) + lType='text/cache-manifest'; + /* если это неизвестный тип файла - + * высылаем его просто как текст + */ + else lType='text/plain'; + + return { + /* if type of file any, but img - + * then we shoud specify charset + */ + 'Content-Type': lType + (lType.indexOf('img')<0?'; charset=UTF-8':''), + 'cache-control': 'max-age='+(31337*21), + 'last-modified': new Date().toString(), + 'content-encoding': pGzip?'gzip':'', + /* https://developers.google.com/speed/docs/best-practices/caching?hl=ru#LeverageProxyCaching */ + 'Vary': 'Accept-Encoding' + }; +}; + +/* + * Главная функция, через которую проихсодит + * взаимодействие, обмен данными с клиентом + * @req - запрос клиента (Request) + * @res - ответ сервера (Response) + */ +CloudServer._controller=function(pReq, pRes) +{ + /* Читаем содержимое папки, + переданное в url + */ + var url = require("url"); + var pathname = url.parse(pReq.url).pathname; + console.log('pathname: '+pathname); + + /* получаем поддерживаемые браузером кодировки*/ + var lAcceptEncoding = pReq.headers['accept-encoding']; + /* запоминаем поддерживает ли браузер + * gzip-сжатие при каждом обращении к серверу + * и доступен ли нам модуль zlib + */ + if (lAcceptEncoding && + lAcceptEncoding.match(/\bgzip\b/) && + Zlib){ + CloudServer.Gzip=true; + }else + CloudServer.Gzip=false; + /* путь в ссылке, который говорит + * что js отключен + */ + var lNoJS_s=CloudFunc.NOJS; + var lFS_s=CloudFunc.FS; + + if(pathname!=='/favicon.ico') + { + console.log("request for " + pathname + " received..."); + var lName; + + /* если в пути нет информации ни о ФС, + * ни об отсутствии js, + * ни о том, что это корневой + * каталог - загружаем файлы проэкта + */ + if(pathname.indexOf(lFS_s)<0 && + pathname.indexOf(lNoJS_s)<0 && + pathname!=='/'){ + /* если имена файлов проекта - загружаем их*/ + /* убираем слеш и читаем файл с текущец директории*/ + //lName=Path.basename(pathname); + + /* добавляем текующий каталог к пути */ + lName='.'+pathname; + console.log('reading '+lName); + /* сохраняем указатель на responce и имя */ + CloudServer.Responses[lName]=pRes; + + /* Берём значение из кэша + * сжатый файл - если gzip-поддерживаеться браузером + * не сжатый - в обратном случае + */ + var lFileData=CloudServer.Cache.get(CloudServer.Gzip?(lName+'_gzip'):lName); + + var lReadFileFunc_f=CloudServer.getReadFileFunc(lName); + /* если там что-то есть передаём данные в функцию + * readFile + */ + if(lFileData){ + console.log('readed from cache'); + /* передаём данные с кэша, + * если gzip включен - сжатые + * в обратном случае - несжатые + */ + lReadFileFunc_f(undefined,lFileData,true); + } + else Fs.readFile(lName,lReadFileFunc_f); + + }else{/* если мы имеем дело с файловой системой*/ + /* если путь не начинаеться с no-js - значит + * js включен + */ + /* убираем пометку cloud, без которой c9.io + * не работает поскольку путь из двух слешей + * (/fs/no-js/) - очень короткий, нужно + * длиннее + */ + + if(pathname.indexOf(lNoJS_s)!==lFS_s.length && pathname!=='/'){ + CloudServer.NoJS=false; + }else pathname=pathname.replace(lNoJS_s,''); + + /* убираем индекс файловой системы */ + if(pathname.indexOf(lFS_s)===0){ + pathname=pathname.replace(lFS_s,''); + /* если посетитель только зашел на сайт + * no-js будет пустым, как и fs + */ + /* если в пути нету fs - посетитель только зашел на сайт + * загружаем его полностью. + */ + }else CloudServer.NoJS=true; + /* если в итоге путь пустой + * делаем его корневым + */ + if(pathname==='')pathname='/'; + + RightDir=pathname; + LeftDir=pathname; + + /* если встретиться пробел - + * меня код символа пробела на пробел + */ + + LeftDir=CloudFunc.replaceSpaces(LeftDir); + RightDir=CloudFunc.replaceSpaces(RightDir); + + /* Проверяем с папкой ли мы имеем дело */ + + /* читаем сновные данные о файле */ + var lStat; + try{ + lStat=Fs.statSync(LeftDir); + }catch(error){ + console.log(error); + CloudServer.Responses[LeftDir]=pRes; + CloudServer.sendResponse('OK',error.toString(),LeftDir); + } + /* если это каталог - + * читаем его содержимое + */ + try{ + /* если установлено сжатие + * меняем название html-файла и + * загружаем сжатый html-файл в дальнейшем + */ + CloudServer.INDEX=(CloudServer.Minify.done.html?'index.min.html':CloudServer.INDEX); + /* + * сохраним указатель на response + */ + CloudServer.Responses[CloudServer.INDEX]=pRes; + if(lStat.isDirectory()) + Fs.readdir(LeftDir,CloudServer._readDir); + /* отдаём файл */ + else if(lStat.isFile()){ + CloudServer.Responses[LeftDir]=pRes; + Fs.readFile(LeftDir,CloudServer.getReadFileFunc(LeftDir)); + console.log('reading file: '+LeftDir); + } + }catch(error){console.log(error);} + } + } +}; + +/* Функция читает ссылку или выводит информацию об ошибке*/ +CloudServer._readDir=function (pError, pFiles) +{ + if(!pError) + { + /* данные о файлах в формате JSON*/ + var lJSON=[]; + var lJSONFile={}; + /* Если мы не в корне добавляем слеш к будующим ссылкам */ + if(LeftDir!=='/') + { + RightDir+='/'; + LeftDir+='/'; + } + + pFiles=pFiles.sort(); + + lJSON[0]={path:LeftDir,size:'dir'}; + var fReturnFalse=function returnFalse(){return false;}; + for(var i=0;i','') + .replace('style.css','all.min.css') + :lIndex; + + lIndex = CloudServer.Minify.done.js?lIndex.replace('client.js','client.min.js'):lIndex; + + lIndex=lIndex.toString().replace('
    ','
    '+lList); + /* меняем title */ + lIndex=lIndex.replace('Cloud Commander', + ''+CloudFunc.setTitle()+''); + /* отображаем панель быстрых клавишь */ + lList=lIndex; + /* если браузер поддерживает gzip-сжатие*/ + lHeader=CloudServer.generateHeaders('text/html',CloudServer.Gzip); + }catch(error){console.log(error);} + }else{ + /* в обычном режиме(когда js включен + * высылаем json-структуру файлов + * с соответствующими заголовками + */ + lList=JSON.stringify(lJSON); + lHeader=CloudServer.generateHeaders('application/json',CloudServer.Gzip); + } + /* если браузер поддерживает gzip-сжатие - сжимаем данные*/ + if(CloudServer.Gzip){ + Zlib.gzip(lList,CloudServer.getGzipDataFunc(lHeader,CloudServer.INDEX)); + } + /* если не поддерживаеться - отсылаем данные без сжатия*/ + else + CloudServer.sendResponse(lHeader,lList,CloudServer.INDEX); + } + else + { + console.log(pError); + CloudServer.sendResponse('OK',pError.toString()); + } +}; + +/* Функция генерирует функция считывания файла + * таким образом, что бы у нас было + * имя считываемого файла + * @pName - полное имя файла + */ +CloudServer.getReadFileFunc = function(pName){ +/* + * @pError - ошибка + * @pData - данные + * @pFromFile - прочитано с файла bool + */ + var lReadFile=function(pError,pData,pFromCache_b){ + if (!pError){ + console.log('file ' + pName + ' readed'); + + /* берём из кэша данные файла + * если их нет в кэше - + * сохраняем + */ + if(!pFromCache_b && CloudServer.Cache.isAllowed) + CloudServer.Cache.set(pName,pData); + /* если кэш есть + * сохраняем его в переменную + * которая до этого будет пустая + * по скольку мы будем вызывать этот метод + * сами, ведь файл уже вычитан + */ + + var lHeader=CloudServer.generateHeaders(pName,CloudServer.Gzip); + /* если браузер поддерживает gzip-сжатие - сжимаем данные*/ + if(CloudServer.Gzip &&!pFromCache_b){ + /* сжимаем содержимое */ + Zlib.gzip(pData,CloudServer.getGzipDataFunc(lHeader,pName)); + } + else{ + /* высылаем несжатые данные */ + CloudServer.sendResponse(lHeader,pData,pName); + } + } + else + { + console.log(pError.path); + if(pError.path!=='passwd.json') + { + console.log(pError); + CloudServer.sendResponse('OK',pError.toString()); + }else{ + CloudServer.sendResponse('OK','passwd.json'); + } + } + }; + return lReadFile; +}; + +/* Функция получает сжатые данные + * @pHeader - заголовок файла + */ +CloudServer.getGzipDataFunc=function(pHeader,pName){ + return function(error,pResult){ + if(!error){ + /* отправляем сжатые данные + * вместе с заголовком + */ + /* если установлена работа с кэшем + * сохраняем сжатые данные + */ + if(CloudServer.Cache.isAllowed){ + /* устанавливаем кєш */ + console.log(pName+' gziped'); + CloudServer.Cache.set(pName+'_gzip',pResult); + } + CloudServer.sendResponse(pHeader,pResult,pName); + } + else{ + console.log(error); + CloudServer.sendResponse(pHeader,error); + } + }; +}; +/* Функция высылает ответ серверу + * @pHead - заголовок + * @pData - данные + * @pName - имя отсылаемого файла + */ +CloudServer.sendResponse = function(pHead, pData,pName){ + /* если у нас есть указатель на responce + * для соответствующего файла - + * высылаем его + */ + var lResponse=CloudServer.Responses[pName]; + if(lResponse){ + lResponse.writeHead(200,pHead); + lResponse.end(pData); + console.log(pName+' sended'); + } +}; + +CloudServer.start(); \ No newline at end of file diff --git a/cloudcmd1/style.css b/cloudcmd1/style.css new file mode 100644 index 00000000..57136168 --- /dev/null +++ b/cloudcmd1/style.css @@ -0,0 +1,317 @@ +/* +@import url(//fonts.googleapis.com/css?family=Droid+Sans+Mono); +*/ + +/* Foundation Icons General Enclosed */ +@font-face { + font-family: 'FoundationIconsGeneralEnclosed'; + src: url('//dl.dropbox.com/u/78163899/mnemonia/fonts/foundation-icons-general-enclosed.woff') format('woff'); + font-weight: normal; + font-style: normal; + +} +/* символьный шрифт от гитхаба*/ +@font-face { + font-family: 'Octicons Regular'; + font-style: normal; + font-weight: normal; + src: local('Octicons Regular'), url('//dl.dropbox.com/u/78163899/mnemonia/fonts/octicons-regular-webfont.woff') format('woff'); +} + +@font-face { + font-family: 'Droid Sans Mono'; + font-style: normal; + font-weight: normal; + src: local('Droid Sans Mono'), local('DroidSansMono'), url('http://themes.googleusercontent.com/static/fonts/droidsansmono/v4/ns-m2xQYezAtqh7ai59hJUYuTAAIFFn5GTWtryCmBQ4.woff') format('woff'); +} + +body{ + font:16px "Droid Sans Mono"; +} + +.menu{ + font: 16px 'Octicons Regular'; + margin-bottom: 0; +} + +.path_icon{ + font-family:'FoundationIconsGeneralEnclosed'; + font-size:30px; + color: #46A4C3;/*#55BF3F; green*/ + text-shadow:black 0 2px 1px; + /* размер иконки и позиция на png-файле*/ + width: 15px; + height: 15px; + display: inline-block; + position: relative; + top: 3px; + left: -4px; +} +.path_icon:hover{ + /* + color:#45D827; + */ + cursor:pointer; +} +.path_icon:active{ + text-shadow:black 0 0 1px; + position: relative; + top: 4px; +} +.icon{ + font-family: 'Octicons Regular'; + font-size:16px; + width:16px; + height:16px; + display:inline-block; + margin-left:0.5%; +} +.error::before{ + content:'\f026'; + cursor:default; + color:rgb(222, 41, 41); + position: relative; + top: -3px; +} +.loading{ + background:url(/img/spinner.gif); + position:relative; + top:1px; +} +.error:hover{ + color:rgba(222, 41, 41, 0.81); +} +.refresh-icon{ + background:url(/img/panel_refresh.png) no-repeat; +} +.refresh-icon:active{ + /*background-position-y: -15px;*/ +background:url(/img/panel_refresh.png) 0 -15px no-repeat; +} +.clear-cache{ + background:url(/img/console_clear.png) -4px -4px no-repeat; + margin-right: 6px; + margin-left: 7px; +} +.clear-cache:active{ + /* + background-position-y: -25px; + */ + top:5px; +} + +.settings:before{ + content:'k'; +} +.links{ + color:red; + } + +.mini-icon { + float: left; + height: 16px; + left: -5px; + margin-left: 6px; + position: relative; + top: 2px; + width: 16px; + /* отступ перед картинкой + * для нормального отображения + * рамки + */ +} +/* freeupex */ +.directory{ + /*list-style-image*/ + background-image:url('/img/dir.png'); + background-repeat: no-repeat; + background-position: 0 0; +} +.text-file{ + /*list-style-image*/ + background-image:url('/img/txt.png'); + background-repeat: no-repeat; + background-position: 0 0; +} +#fm{ + height:90%; + overflow-y: scroll; +} +.fm_header{ + font-weight: bold; +} +#path{ + margin-left:1.5%; +} +#left{ + float:left; + width:90%; +} +/* фон файла, на котором курсор*/ +.current-file{ + border: 2px solid rgba(49, 123, 249, .40); +} +.selected-file{ + background-color: rgba(49, 123, 249, .40); + color:white; +} +#right{ + float:right; +} +.panel{ + display: table; + width:45%; +} +#keyspanel{ + text-align: center; +} +/* информация о файлах и папках*/ +.name{ + float: left; + width: 37%; +} +.size{ + float:left; + width:16%; + /* Ставим выравнивание, + * что бы размер был в + * одной ровной колонке + */ + text-align: right; + /* Ставим отступ, что бы + * size не налазил на uid + * (owner) + */ + margin-right: 27px; +} +.owner{ +} +.mode{ + float: right; + width: 25%; +} + +ul,li{list-style-type:none;} +button{ + width:10%; +} +a{ + text-decoration:none; +} +a:hover, a:active { cursor:pointer;outline: 0; color: #06e; } +a:focus { outline: thin dotted; } + +/* Если размер окна очень маленький + * располагаем имя и атрибуты файла + * друг-под-другом +*/ +/* responsive design */ +@media only screen and (max-width: 600px){ + #left{ + width:90% !important; + } + .panel >li{ + margin:10px; + } + /* если правая панель не помещаеться - прячем её */ + #right{ + display:none; + } + /* текущий файл под курсором */ +.current-file{ + background-color: rgba(49, 123, 249, .40); + color:white; + } + /* делаем иконки под курсом белыми*/ +.current-file > .mini-icon{ + color:white; + } +.current-file > .text-file::before{ + color:white; + } + +/* меняем иконки на шрифтовые*/ + .mini-icon { + font: 60px 'Octicons Regular'; + width: 40%; + height: 0; + margin-left: 0; + float: right; + position: relative; + top: -17px; + + color: rgba(246, 224, 124, 0.56); + } + .directory::before{ + content: '\f216'; + } + .text-file::before{ + color: rgba(26, 224, 124, 0.56); + content: '\f211'; + } + .text-file{ + background-image:none; + } + + + + /* убираем заголовок*/ + .fm_header{ + display:none; + } + .mode,.size,.owner{ + /* располагаем элементы + * один под другим + */ + display: table; + float: none; + width: 0; + + text-align: left; + } + /* выводим заголовки рядом с полями */ + .name::before{ + content: 'name:'; + font-weight: bold; + font-size: 13px; + } + .mode::before{ + content: 'mode:'; + font-weight: bold; + font-size: 13px; + } + .size::before{ + content: 'size:'; + font-weight: bold; + font-size: 13px; + } + .owner::before{ + content: 'owner:'; + font-weight: bold; + font-size: 13px; + } + + .name{ + float: none; + width:100%; + font-size: 18px; + } +} +@media only screen and (min-width: 601px) and (max-width: 767px){ + #left{ + width:90% !important; + } + #right{ + display:none; + } +} + +@media only screen and (min-width:767px) and (max-width: 1060px){ + #left{ + width:90% !important; + } + /* если правая панель не помещаеться - прячем её */ + #right{ + display:none; + } +} \ No newline at end of file diff --git a/cloudcmd1/test.sh b/cloudcmd1/test.sh new file mode 100644 index 00000000..6b68a51f --- /dev/null +++ b/cloudcmd1/test.sh @@ -0,0 +1,4 @@ +#!/bin/sh +npm i -g jshint +echo "jshint server.js client.js lib/cloudfunc.js" +jshint --config ./.jshintrc ./server.js ./client.js ./lib/cloudfunc.js \ No newline at end of file diff --git a/css/reset.css b/css/reset.css new file mode 100644 index 00000000..23504a59 --- /dev/null +++ b/css/reset.css @@ -0,0 +1,90 @@ + +/* ============================================================================= + Base + ========================================================================== */ + +/* + * 1. Correct text resizing oddly in IE6/7 when body font-size is set using em units + * 2. Prevent iOS text size adjust on device orientation change, without disabling user zoom: h5bp.com/g + */ + +html { font-size: 100%; -webkit-text-size-adjust: 100%; -ms-text-size-adjust: 100%; font-family: sans-serif; color: #222;} +body { margin: 0; font-size: 1em; line-height: 1.4; } + +/* + * Remove text-shadow in selection highlight: h5bp.com/i + * These selection declarations have to be separate + * Also: hot pink! (or customize the background color to match your design) + */ +/* +::-moz-selection { background: #fe57a1; color: #fff; text-shadow: none; } + ::selection { background: #fe57a1; color: #fff; text-shadow: none; } +*/ +::selection { text-shadow: none; opacity: 0;} + + +/* ============================================================================= + Links + ========================================================================== */ + +a {text-decoration:none; color: #00e; } +a:visited { color: #551a8b; } +a:hover { color: #06e; } +a:focus { outline: thin dotted; } + +/* Improve readability when focused and hovered in all browsers: h5bp.com/h */ +a:hover, a:active { outline: 0; } + +ul{ margin: 1em 0; padding: 0 0 0 40px; } + +/* + * 1. Display hand cursor for clickable form elements + * 2. Allow styling of clickable form elements in iOS + * 3. Correct inner spacing displayed oddly in IE7 (doesn't effect IE6) + */ + + +/* ============================================================================= + Chrome Frame Prompt + ========================================================================== */ + +.chromeframe { margin: 0.2em 0; background: #ccc; color: black; padding: 0.2em 0; } + + +/* ==|== non-semantic helper classes ======================================== + Please define your styles before this section. + ========================================================================== */ + +/* For image replacement */ +.ir { display: block; border: 0; text-indent: -999em; overflow: hidden; background-color: transparent; background-repeat: no-repeat; text-align: left; direction: ltr; *line-height: 0; } +.ir br { display: none; } + +/* Hide from both screenreaders and browsers: h5bp.com/u */ +.hidden { display: none !important; visibility: hidden; } + +/* Hide only visually, but have it available for screenreaders: h5bp.com/v */ +.visuallyhidden { border: 0; clip: rect(0 0 0 0); height: 1px; margin: -1px; overflow: hidden; padding: 0; position: absolute; width: 1px; } + +/* Extends the .visuallyhidden class to allow the element to be focusable when navigated to via the keyboard: h5bp.com/p */ +.visuallyhidden.focusable:active, .visuallyhidden.focusable:focus { clip: auto; height: auto; margin: 0; overflow: visible; position: static; width: auto; } + +/* Hide visually and from screenreaders, but maintain layout */ +.invisible { visibility: hidden; } + +/* Contain floats: h5bp.com/q */ +.clearfix:before, .clearfix:after { content: ""; display: table; } +.clearfix:after { clear: both; } +.clearfix { *zoom: 1; } + +/* ==|== print styles ======================================================= + Print styles. + Inlined to avoid required HTTP connection: h5bp.com/r + ========================================================================== */ + +@media print { + * { background: transparent !important; color: black !important; box-shadow:none !important; text-shadow: none !important; filter:none !important; -ms-filter: none !important; } /* Black prints faster: h5bp.com/s */ + a, a:visited { text-decoration: underline; } + a[href]:after { content: " (" attr(href) ")"; } + .ir a:after, a[href^="javascript:"]:after, a[href^="#"]:after { content: ""; } /* Don't show links for images, or javascript/internal links */ + @page { margin: 0.5cm; } +} \ No newline at end of file diff --git a/css/style.css b/css/style.css new file mode 100644 index 00000000..57136168 --- /dev/null +++ b/css/style.css @@ -0,0 +1,317 @@ +/* +@import url(//fonts.googleapis.com/css?family=Droid+Sans+Mono); +*/ + +/* Foundation Icons General Enclosed */ +@font-face { + font-family: 'FoundationIconsGeneralEnclosed'; + src: url('//dl.dropbox.com/u/78163899/mnemonia/fonts/foundation-icons-general-enclosed.woff') format('woff'); + font-weight: normal; + font-style: normal; + +} +/* символьный шрифт от гитхаба*/ +@font-face { + font-family: 'Octicons Regular'; + font-style: normal; + font-weight: normal; + src: local('Octicons Regular'), url('//dl.dropbox.com/u/78163899/mnemonia/fonts/octicons-regular-webfont.woff') format('woff'); +} + +@font-face { + font-family: 'Droid Sans Mono'; + font-style: normal; + font-weight: normal; + src: local('Droid Sans Mono'), local('DroidSansMono'), url('http://themes.googleusercontent.com/static/fonts/droidsansmono/v4/ns-m2xQYezAtqh7ai59hJUYuTAAIFFn5GTWtryCmBQ4.woff') format('woff'); +} + +body{ + font:16px "Droid Sans Mono"; +} + +.menu{ + font: 16px 'Octicons Regular'; + margin-bottom: 0; +} + +.path_icon{ + font-family:'FoundationIconsGeneralEnclosed'; + font-size:30px; + color: #46A4C3;/*#55BF3F; green*/ + text-shadow:black 0 2px 1px; + /* размер иконки и позиция на png-файле*/ + width: 15px; + height: 15px; + display: inline-block; + position: relative; + top: 3px; + left: -4px; +} +.path_icon:hover{ + /* + color:#45D827; + */ + cursor:pointer; +} +.path_icon:active{ + text-shadow:black 0 0 1px; + position: relative; + top: 4px; +} +.icon{ + font-family: 'Octicons Regular'; + font-size:16px; + width:16px; + height:16px; + display:inline-block; + margin-left:0.5%; +} +.error::before{ + content:'\f026'; + cursor:default; + color:rgb(222, 41, 41); + position: relative; + top: -3px; +} +.loading{ + background:url(/img/spinner.gif); + position:relative; + top:1px; +} +.error:hover{ + color:rgba(222, 41, 41, 0.81); +} +.refresh-icon{ + background:url(/img/panel_refresh.png) no-repeat; +} +.refresh-icon:active{ + /*background-position-y: -15px;*/ +background:url(/img/panel_refresh.png) 0 -15px no-repeat; +} +.clear-cache{ + background:url(/img/console_clear.png) -4px -4px no-repeat; + margin-right: 6px; + margin-left: 7px; +} +.clear-cache:active{ + /* + background-position-y: -25px; + */ + top:5px; +} + +.settings:before{ + content:'k'; +} +.links{ + color:red; + } + +.mini-icon { + float: left; + height: 16px; + left: -5px; + margin-left: 6px; + position: relative; + top: 2px; + width: 16px; + /* отступ перед картинкой + * для нормального отображения + * рамки + */ +} +/* freeupex */ +.directory{ + /*list-style-image*/ + background-image:url('/img/dir.png'); + background-repeat: no-repeat; + background-position: 0 0; +} +.text-file{ + /*list-style-image*/ + background-image:url('/img/txt.png'); + background-repeat: no-repeat; + background-position: 0 0; +} +#fm{ + height:90%; + overflow-y: scroll; +} +.fm_header{ + font-weight: bold; +} +#path{ + margin-left:1.5%; +} +#left{ + float:left; + width:90%; +} +/* фон файла, на котором курсор*/ +.current-file{ + border: 2px solid rgba(49, 123, 249, .40); +} +.selected-file{ + background-color: rgba(49, 123, 249, .40); + color:white; +} +#right{ + float:right; +} +.panel{ + display: table; + width:45%; +} +#keyspanel{ + text-align: center; +} +/* информация о файлах и папках*/ +.name{ + float: left; + width: 37%; +} +.size{ + float:left; + width:16%; + /* Ставим выравнивание, + * что бы размер был в + * одной ровной колонке + */ + text-align: right; + /* Ставим отступ, что бы + * size не налазил на uid + * (owner) + */ + margin-right: 27px; +} +.owner{ +} +.mode{ + float: right; + width: 25%; +} + +ul,li{list-style-type:none;} +button{ + width:10%; +} +a{ + text-decoration:none; +} +a:hover, a:active { cursor:pointer;outline: 0; color: #06e; } +a:focus { outline: thin dotted; } + +/* Если размер окна очень маленький + * располагаем имя и атрибуты файла + * друг-под-другом +*/ +/* responsive design */ +@media only screen and (max-width: 600px){ + #left{ + width:90% !important; + } + .panel >li{ + margin:10px; + } + /* если правая панель не помещаеться - прячем её */ + #right{ + display:none; + } + /* текущий файл под курсором */ +.current-file{ + background-color: rgba(49, 123, 249, .40); + color:white; + } + /* делаем иконки под курсом белыми*/ +.current-file > .mini-icon{ + color:white; + } +.current-file > .text-file::before{ + color:white; + } + +/* меняем иконки на шрифтовые*/ + .mini-icon { + font: 60px 'Octicons Regular'; + width: 40%; + height: 0; + margin-left: 0; + float: right; + position: relative; + top: -17px; + + color: rgba(246, 224, 124, 0.56); + } + .directory::before{ + content: '\f216'; + } + .text-file::before{ + color: rgba(26, 224, 124, 0.56); + content: '\f211'; + } + .text-file{ + background-image:none; + } + + + + /* убираем заголовок*/ + .fm_header{ + display:none; + } + .mode,.size,.owner{ + /* располагаем элементы + * один под другим + */ + display: table; + float: none; + width: 0; + + text-align: left; + } + /* выводим заголовки рядом с полями */ + .name::before{ + content: 'name:'; + font-weight: bold; + font-size: 13px; + } + .mode::before{ + content: 'mode:'; + font-weight: bold; + font-size: 13px; + } + .size::before{ + content: 'size:'; + font-weight: bold; + font-size: 13px; + } + .owner::before{ + content: 'owner:'; + font-weight: bold; + font-size: 13px; + } + + .name{ + float: none; + width:100%; + font-size: 18px; + } +} +@media only screen and (min-width: 601px) and (max-width: 767px){ + #left{ + width:90% !important; + } + #right{ + display:none; + } +} + +@media only screen and (min-width:767px) and (max-width: 1060px){ + #left{ + width:90% !important; + } + /* если правая панель не помещаеться - прячем её */ + #right{ + display:none; + } +} \ No newline at end of file diff --git a/img/console_clear.png b/img/console_clear.png new file mode 100644 index 0000000000000000000000000000000000000000..f5739eb13b9c313415b984ea96ad47505c9dd7e7 GIT binary patch literal 1344 zcmV-G1;6@1^@s6nD_O6000FCNkl-&xG_lrq5JXm++URcxOi=C%>~R;c#Bt8S0&&E5Hja3i;IivGcz-!xw-j(mw07mC2V0~ z;XtF&kmcp&X`H*^e0_3qlBm^n#Mjqvm9rQk$K>SX*p`+S-N?uYnV6U$80qo&_&BMp zttAqP^fB7Ga1t*qEzyzgK=6S~7W7+VVo$x&rxRZ3u> zOfScE{m9YoW0S?0$3N@qAL;O@dpS8dq`SMD^z`)5`8}$rs7MJ22;8Le+tk!Vu3vvI z!(?$5Q{(>hy!xq2Yfi<$MlV3 zT(1d)LSa0e6z&A(cxnx<{$qoV*c^ZBIXzWY+~N=&nD&_|7>F3@y{ma9sg`% zp7GBv<{ba5Vh0BYDz-33{2R73oW26NTrQ=B!yNH%C_rJHCaU_N5N$qE32|%B{f#-~q%u@n9U*FL(UAf;`X*zUN6V z<8U>IJwOj=0A-*E6mq19>D$1#!~$z;>#y)d1+u|sKmpP?qM&^lM>(AL1(ueURrCUj zkjo9S;H(zlCHRhtkKcY4a$k%l#EkQ#5UTfsHptZ)KoQUfYM01MdQDrp+WnM zQ5ORId5$zbKE8NvZcdBHqA~T0L?Zbb<#fvs|CcU#Z=USKDt2~u&OpRJG>-rI`FWio z{(XFWwry-|vN(z3;^K;t)K8L! z1qDAfj(;RHYWJhlfWT z+1Z`>#$@sN^R82wnVC~+wR+#%+j~1dKYzeZ^;+}vH<;Abqg4LpGk(!VfLrag-ol_>97 zTiVgl@qtM6>Z($y98{?)v>c=gIKLH$M54RTD?(0A&fOO;zP@dul%mu-QCuY0K^f*M zn{cI5r#}9%ZhhU|-9NImwN2$)=xJZ-psrJm|9=3w$r4qVmLG}$0000x(K@^6+>g^d@v4;gkbWsEoXE%32*i1tcpTNXd5CcIl)ECgqz|2rE6EW}s7R?kl za1q`0GCkMruC6-2LANtwVlsgzsp4?{@7$`KBv!G66>Vie3h?3OmEEkjwdLG0PgLVi z`!N((f$A@n17Ldj#`};0I3@iHJ5M{#IZz|UIYRm4(!uV7eYIYIwQf&}_2J~}>pQ^n z6o8--^T(=hkBNQ_k{-_GWE;FMW7!p}f{NG3nHZ{D5<3d8&tLh%a4AqqnjMkr3m&fkMdECD3N5}Unig5wy40;>lo4j~k+e}v)` zR6)J8Mk*u=SpB`p6o)7j?S0T@9?bz#m@l>gc*zk__|*!FMcHwP!gwLJvS~9c0px8E zW-!=9%H93I*%*Z8=x$dA&dD~$D#ws+K{GQN()gz!9L&jK+m?%ta#Ng#%LpbBNoY3B#?};^W4ea|M9+}o zHdC0d@8fOgzx&s(hgNN>reIf=V)iIwe@=tlS^Z^U*t?c$nwvM@PHQ5tkP zH-)B-Mq`7fP!!Eyd~nL83rQ4)|3~a@{N+69jegYHY3LuZxR?j&Rg( zPR07x9`1ZD#|O8G-ntj8_HQXyY9i(tVWd9NjbO4rIv&%;esZ6qJG=idk${yrEWlMrvxH7xey@*#~8ywwu|0 z)svn+awvo8ooru?o>KJ^1|_LLspI?9dj{jttL3#^3xM*lrKE|^FL5>V|Z6PM$qllk=|_^ZK-V(${mTKO4ZY-M}wa6qM=bJ@09jxyC2Hc zBF@xIj+>6SwwiwW(&F$#Y3Sl-!9sR+nMfeV>u)|N(^D%|{T_ab#w7d}0-RCWfL>r2Y@ZJK_=UpZo#K^zc-BA}1#R0000g($p8XB6Knwp!NTUuILTU)PQz1r5+*52N3GMT!%x_Wwg zdV6~Z1_lNP2Zx4+hKGkoMn*dAeCMNFOxidLAIW;vkJv}`$GxOlVgU62_ zKY8-x>C>lkb8`y|3yX`3OG``3%gZY(E32!kYiny}v-#!Am+R~6ymi9X@OZ5|=$3Ac*%IgT+Ds5+OGdk_-B4F{dAcdAsVTz+%sNqp=LM4kzb?{0I z;Bz=G_C%7MC{enBL1!z)8|7O>CCWe^*>Uq0Hiat%awm$Q!Y#nx%ULG0cP#MSC7}pi znBEk3;4eG{f*4FWj|O%l84+(L?P{oSw#38uvnG)ZZ+hDkFoWN&DomB1{ zjl0?f$RtSX%!3ZVRRQYWApJ;=oN@V{ch5`Pp%I(?a3*b!(AJ-(x=?je>q56RP z`&&@0ahx7+72}@1-1+BKffxy;hb*QAAxO|FHP9nNxoauxL_2-NktKHRL3+tnwy?RjN$+Zicb zGBLx;8e@gaVDK}69D|}nX@oXnI|!S}2JYnGOe3(s;UE-Jn;n9SGu=fL!)KMH3elT) zq@5g&on39$(Z3#Ol<^%)PSXVo@E&q6`cSTrjO&%y`>vBZRF7tVaM(pbqh&-VhzUFx zAqs1hWVaY)*e%^*0kMXxkk*L*^>%P&;+jFh5-IyB8C89Gd22-x+jxV%#Di|LEwkjyu(vg~l-y8JRso0YmVQ5EkVH9_bWdmriPn;Xz0HU?r-}Ym*JU~Gu z#H!z-Sig~NtEtil^EbXk5q|z4muDm>JIP0rwG7WD3S+9GBJ~;heG|L%tnJOt3;ODZ z-=AxhB~Tm|@--{&wt!9Dq!z~jdjgQsj;d1ui)`r{g#3l@`Y+o|m4+ohb8%lK3Tosj z`cr?TkjIV;SJxUp<&q1u2@0f zfjG4{K?pdGK(syql%&93%2zra#Xu0BrOCKFA;`ks$&+C#5QQ<|d}62BjvZR2H60wE-&H;pyTSqH(@-Vl>|&1p(LP>kg~E zYiz5X^`c$+%8#zC{u)yfe-5 zmgid={Z3k(ERKCKrE7DF;=x4^O+ pzO8rLO8p|Ip=x)jHOtWj`bJBmKdh_V<`47(gQu&X%Q~loCIFbEay|e6 literal 0 HcmV?d00001 diff --git a/index.html b/index.html new file mode 100644 index 00000000..6524a912 --- /dev/null +++ b/index.html @@ -0,0 +1,54 @@ + + + + + + + Cloud Commander + + + + + + + + + + +
    +
    + + + + \ No newline at end of file diff --git a/lib/README.md b/lib/README.md new file mode 100644 index 00000000..a741f80c --- /dev/null +++ b/lib/README.md @@ -0,0 +1,5 @@ +Cloud Commander Libraries +=============== +**Cloud Commander Libraries** - dir thet contains scripts, thet uses +on client and server side, and modules, wich is not necessary +for CloudCommander work, but they adds some sugor. \ No newline at end of file diff --git a/lib/client/keyBinding.js b/lib/client/keyBinding.js new file mode 100644 index 00000000..2416002e --- /dev/null +++ b/lib/client/keyBinding.js @@ -0,0 +1,248 @@ +var CloudCommander; +var CloudFunc; +CloudCommander.keyBinding=(function(){ + "use strict"; + var key_event=function(event){ + /* + * Делаем допущение что перезагружать Cloud Commander + * посетителям не придёться, в любом случае, параметр + * должен быть опциональным и должна быть возможность + * его отключить. В любом случае, кроме хакеров и + * разработчиков (при чём сомнительно, что хакерам + * это пригодиться), функция перезагрузки никому не + * нужна, поскольку загружать весь дополнительный + * контент снова (js,css) в готовой версии нет + * необходимости. + * + */ + //console.log(event.keyCode); + var lCurrentFile; + var lName; + /* если клавиши можно обрабатывать*/ + if(CloudCommander.keyBinded){ + /* если нажали таб: + * переносим курсор на + * правую панель, если + * мы были на левой и + * наоборот + */ + if(event.keyCode===9){ + console.log('Tab pressed'); + try{ + lCurrentFile=document.getElementsByClassName(CloudCommander.CURRENT_FILE)[0]; + }catch(error){console.log(error);} + } + /* навигация по таблице файлов*/ + /* если нажали клавишу вверх*/ + else if(event.keyCode===38){ + /* получаем выдленный файл*/ + lCurrentFile=document.getElementsByClassName(CloudCommander.CURRENT_FILE); + /* если ненайдены выделенные файлы - выходим*/ + if(lCurrentFile.length===0)return; + lCurrentFile=lCurrentFile[0]; + /* если это строка существет и + * если она не заголовок + * файловой таблицы + */ + if(lCurrentFile.previousSibling && + lCurrentFile.previousSibling.className!=='fm_header' ){ + /* убираем выделение с текущего элемента */ + lCurrentFile.className=''; + /* и выделяем предыдущую строку*/ + lCurrentFile.previousSibling.className=CloudCommander.CURRENT_FILE; + event.preventDefault(); + } + } + /* если нажали клавишу в низ*/ + else if(event.keyCode===40){ + /* получаем выдленный файл*/ + lCurrentFile=document.getElementsByClassName(CloudCommander.CURRENT_FILE); + /* если ненайдены выделенные файлы - выходим*/ + if(lCurrentFile.length===0)return; + lCurrentFile=lCurrentFile[0]; + /* если это не последняя строка */ + if(lCurrentFile.nextSibling){ + /* убираем с него выделение */ + lCurrentFile.className=''; + /* выделяем следующую строку*/ + lCurrentFile.nextSibling.className=CloudCommander.CURRENT_FILE; + event.preventDefault(); + } + } + /* если нажали клавишу page up или Home + * переходим к самому верхнему + * элементу + */ + else if(/*event.keyCode===33 ||*/ event.keyCode===36){ + lCurrentFile=document.getElementsByClassName(CloudCommander.CURRENT_FILE)[0]; + /* убираем выделение с текущего файла*/ + lCurrentFile.className=''; + /* получаем первый элемент*/ + lCurrentFile.parentElement.firstElementChild + /* пропускаем путь и заголовки столбиков*/ + .nextElementSibling.nextElementSibling + /* выделяем верхий файл */ + .className=CloudCommander.CURRENT_FILE; + } + /* если нажали клавишу page down или End + * выделяем последний элемент + */ + else if(/*event.keyCode===34 ||*/ event.keyCode===35){ + lCurrentFile=document.getElementsByClassName(CloudCommander.CURRENT_FILE)[0]; + /* снимаем выделение с текущего файла*/ + lCurrentFile.className=''; + /* выделяем самый нижний файл */ + lCurrentFile.parentElement.lastElementChild.className=CloudCommander.CURRENT_FILE; + } + /* если нажали Enter - открываем папку*/ + else if(event.keyCode===13){ + lCurrentFile=document.getElementsByClassName(CloudCommander.CURRENT_FILE); + /* если ненайдены выделенные файлы - выходим*/ + if(!lCurrentFile.length)return; + lCurrentFile=lCurrentFile[0]; + /* из него достаём спан с именем файла*/ + lName=lCurrentFile.getElementsByClassName('name'); + /* если нету (что вряд ли) - выходим*/ + if(!lName)return false; + /* достаём все ссылки*/ + var lATag=lName[0].getElementsByTagName('a'); + /* если нету - выходим */ + if(!lATag)return false; + /* получаем ссылку на каталог, + * что на уровень выше + */ + /* получаем имя каталога в котором находимся*/ + var lHref; + try{ + lHref=lCurrentFile.parentElement.getElementsByClassName('path')[0].innerText; + }catch(error){console.log('error');} + lHref=CloudFunc.removeLastSlash(lHref); + var lSubstr=lHref.substr(lHref,lHref.lastIndexOf('/')); + lHref=lHref.replace(lSubstr+'/',''); + + /* вызываем ajaxload привязанный через changelinks + * пробулем нажать на ссылку, если не получиться + * (opera, ie), вызываем событие onclick, + * которое пока не прописано у файлов + */ + + if(lCurrentFile.onclick)lCurrentFile.onclick(true); + else try{ + lATag[0].click(); + } + catch(error){ + console.log(error); + } + } + /* если нажали +r */ + else if(event.keyCode===82 && + event.ctrlKey){ + console.log('+r pressed'); + console.log('reloading page...'); + console.log('press +q to remove all key-handlers'); + + /* обновляем страницу, */ + /* Загружаем содержимое каталога + * при этом данные берём всегда из + * сервера, а не из кэша + * (обновляем кэш) + */ + /* Программно нажимаем на кнопку перезагрузки + * содержимого каталога + */ + var lRefreshIcon=document.getElementsByClassName(CloudFunc.REFRESHICON); + if(lRefreshIcon)lRefreshIcon=lRefreshIcon[0]; + if(lRefreshIcon){ + /* находим файл который сейчас выделен */ + lCurrentFile=document.getElementsByClassName(CloudCommander.CURRENT_FILE); + if(lCurrentFile.length>0)lCurrentFile=lCurrentFile[0]; + /* получаем название файла*/ + var lSelectedName=lCurrentFile.getElementsByTagName('a')[0].innerText; + /* если нашли элемент нажимаем него + * а если не можем - нажимаем на + * ссылку, на которую повешен eventHandler + * onclick + */ + if(lRefreshIcon.click)lRefreshIcon.parentElement.click(); + else lRefreshIcon.parentElement.onclick(); + + /* перебираем файлы левой панели + * в поисках подсвеченого файла + */ + var lLeft=document.getElementById('left'); + if(lLeft){ + /* перебираем все файлы в панели */ + var lLi=lLeft.getElementsByTagName('li'); + lCurrentFile.className=''; + /* начинаем с 2-ух, по скольку + * 0 - это путь + * 1 - это заголовок файловой таблицы + */ + for(var i=2;i+d чистим кэш */ + else if(event.keyCode===68 && + event.ctrlKey){ + console.log('+d pressed'); + console.log('clearing cache...'); + console.log('press +q to remove all key-handlers'); + + var lClearCache=document.getElementById('clear-cache'); + if(lClearCache && lClearCache.onclick)lClearCache.onclick(); + + event.preventDefault();//запрет на дальнейшее действие + } + /* если нажали +q + * убираем все обработчики + * нажатий клавиш + */ + else if(event.keyCode===81 && + event.altKey){ + //document.removeEventListener('keydown', key_event,false); + console.log('+q pressed'); + console.log('+r reload key-handerl - removed'); + console.log('+s clear cache key-handler - removed'); + console.log('press +s to to set them'); + + /* обработчик нажатий клавиш снят*/ + CloudCommander.keyBinded=false; + } + } + /* если нажали +s + * устанавливаем все обработчики + * нажатий клавиш + */ + else if(event.keyCode===83 && + event.altKey){ + /* + document.addEventListener('keydown', key_event,false); + */ + /* обрабатываем нажатия на клавиши*/ + CloudCommander.keyBinded=true; + + console.log('+s pressed'); + console.log('+r reload key-handerl - set'); + console.log('+s clear cache key-handler - set'); + console.log('press +q to remove them'); + } + + return false; + }; + /* добавляем обработчик клавишь */ + if(document.addEventListener) + document.addEventListener('keydown', key_event,false); + else document.onkeypress=key_event; + /* клавиши назначены*/ + CloudCommander.keyBinded=true; +}); \ No newline at end of file diff --git a/lib/cloudfunc.js b/lib/cloudfunc.js new file mode 100644 index 00000000..231f36dd --- /dev/null +++ b/lib/cloudfunc.js @@ -0,0 +1,504 @@ +"use strict"; +/* Модуль, содержащий функции, которые будут работать + * и на клиенте и на сервере + * + * Правила названий: + * varName - имя функции + * lVarName - имя локальной переменной + * pVarName - имя параметра + * fVarName - имя функции созданной внутри функции + * VARNAME - имя константы + * + * Типы переменных: + * varNameS - строка + * varNameN - число + * varNameO - обьект + * varNameM - массив + */ + +var CloudFunc={ + /* Путь с которым мы сейчас работаем */ + Path :'', + /* КОНСТАНТЫ (общие для клиента и сервера)*/ + /* название программы */ + NAME :'Cloud Commander', + /* если в ссылке будет эта строка - + * в браузере js отключен + */ + NOJS : '/no-js', + FS : '/c/f/s', + /* название css-класа кнопки обновления файловой структуры*/ + REFRESHICON : 'refresh-icon', + /* id панелей с файлами */ + LEFTPANEL : 'left', + RIGHTPANEL : 'right' + /* name of direcotory with libs */ +}; + +/* + * Функция убирает последний слеш, + * если он - последний символ строки + */ +CloudFunc.removeLastSlash = function(pPath){ + if(typeof pPath==='string') + return (pPath.lastIndexOf('/')===pPath.length-1)? + pPath.substr(pPath, pPath.length-1):pPath; + else return pPath; +}; +/* + * Функция меняет код символа пробела на пробел + * в переданной строке + * @pPath - строка + */ +CloudFunc.replaceSpaces = function(pPath){ + if(pPath.indexOf('%20')>0){ + do{ + pPath=pPath.replace('%20',' '); + }while(pPath.indexOf('%20')>0); + } + return pPath; +}; + +/* Функция возвращает заголовок веб страницы */ +CloudFunc.setTitle = function(){ + + return CloudFunc.Path===''?CloudFunc.NAME: + CloudFunc.Path + + ' - ' + + CloudFunc.NAME; +}; +/* Функция переводит права из цыфрового вида в символьный + * @pPerm_s - строка с правами доступа + * к файлу в 8-миричной системе + */ +CloudFunc.convertPermissionsToSymbolic= function(pPerm_s){ + /* + S_IRUSR 0000400 protection: readable by owner + S_IWUSR 0000200 writable by owner + S_IXUSR 0000100 executable by owner + S_IRGRP 0000040 readable by group + S_IWGRP 0000020 writable by group + S_IXGRP 0000010 executable by group + S_IROTH 0000004 readable by all + S_IWOTH 0000002 writable by all + S_IXOTH 0000001 executable by all + */ + if(pPerm_s===undefined) return; + + /* тип файла */ + var lType=pPerm_s.charAt(0); + + switch (lType-0) { + case 1: /* обычный файл */ + lType='-'; + break; + case 2: /* байт-ориентированное (символьное) устройство*/ + lType='c'; + break; + case 4: /* каталог */ + lType='d'; + break; + default: + lType='-'; + } + + /* оставляем последние 3 символа*/ + pPerm_s=pPerm_s.length>5?pPerm_s.substr(3):pPerm_s.substr(2); + + /* Рекомендации гугла советуют вместо string[3] + * использовать string.charAt(3) + */ +/* + http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml?showone=Standards_features#Standards_features + + Always preferred over non-standards featuresFor + maximum portability and compatibility, always + prefer standards features over non-standards + features (e.g., string.charAt(3) over string[3] + and element access with DOM functions instead + of using an application-specific shorthand). +*/ + /* Переводим в двоичную систему */ + var lOwner=(pPerm_s[0]-0).toString(2); + var lGroup=(pPerm_s[1]-0).toString(2); + var lAll =(pPerm_s[2]-0).toString(2); + /* + console.log(lOwner+' '+lGroup+' '+lAll); + */ + /* переводим в символьную систему*/ + var lPermissions=//lType+' '+ + (lOwner[0]-0>0?'r':'-')+ + (lOwner[1]-0>0?'w':'-')+ + (lOwner[2]-0>0?'x':'-')+ + ' ' + + (lGroup[0]-0>0?'r':'-')+ + (lGroup[1]-0>0?'w':'-')+ + (lGroup[2]-0>0?'x':'-')+ + ' ' + + (lAll[0]-0>0?'r':'-')+ + (lAll[1]-0>0?'w':'-')+ + (lAll[2]-0>0?'x':'-'); + /* + console.log(lPermissions); + */ + return lPermissions; +}; + +/* Функция конвертирует права доступа к файлам из символьного вида + * в цыфровой + */ +CloudFunc.convertPermissionsToNumberic= function(pPerm_s){ + /* если передана правильная строка, конвертированная + * функциец convertPermissionsToSymbolic + */ + if(!pPerm_s || pPerm_s.length!==11)return pPerm_s; + + var lOwner= (pPerm_s[0]==='r'?4:0) + + (pPerm_s[1]==='w'?2:0) + + (pPerm_s[2]==='x'?1:0); + var lGroup= (pPerm_s[4]==='r'?4:0) + + (pPerm_s[5]==='w'?2:0) + + (pPerm_s[6]==='x'?1:0); + var lAll = (pPerm_s[8]==='r'?4:0) + + (pPerm_s[9]==='w'?2:0) + + (pPerm_s[10]==='x'?1:0); + /* добавляем 2 цыфры до 5 */ + return '00'+lOwner+lGroup+lAll; +}; +/* Функция получает короткие размеры + * конвертируя байт в килобайты, мегабойты, + * гигайбайты и терабайты + * @pSize - размер в байтах + */ +CloudFunc.getShortedSize=function(pSize){ + /* if pSize=0 - return it */ + if(!pSize)return pSize; + + /* Константы размеров, что используются + * внутри функции + */ + var l1BMAX=1024; + var l1KBMAX=1048576; + var l1MBMAX=1073741824; + var l1GBMAX=1099511627776; + var l1TBMAX=1125899906842624; + + var lShorted; + + if(pSize2){ + if(folders[0].lastIndexOf('/')===folders[0].length) + LPrevDir=folders[1]; + else LPrevDir=folders[2]; + }else LPrevDir='/'; + */ + /* ################################### */ + + /* Формируем ссылки на каждый каталог в пути */ + var lHref=''; + var lHrefEnd=''; + + var lHtmlPath; + /* путь в ссылке, который говорит + * что js отключен + */ + var lNoJS_s=CloudFunc.NOJS; + var lFS_s=CloudFunc.FS; + /* корневой каталог */ + lHtmlPath=lHref+lFS_s+lNoJS_s+lTitle+'"/"'+_l+'/'+lHrefEnd; + for(i=folders.length-1;i>0;i--) + { + var lUrl=folders[i]; + var lShortName=lUrl.replace(lUrl.substr(lUrl,lUrl.lastIndexOf('/')+1),''); + if(i!==1) + { + lHtmlPath+=lHref+lFS_s+lNoJS_s+lUrl+lTitle+lUrl+_l+lShortName+lHrefEnd+'/'; + } + else + lHtmlPath+=lShortName+'/'; + } + /* *** */ + return lHtmlPath; +}; + +/* + * Функция ищет в имени файла расширение + * и если находит возвращает true + * @pName - получает имя файла + * @pExt - расширение + */ +CloudFunc.checkExtension=function(pName,pExt) +{ + /* если длина имени больше + * длинны расширения - + * имеет смысл продолжать + */ + if(pName.length>pExt.length){ + var lLength=pName.length; /* длина имени*/ + var lExtNum=pName.lastIndexOf(pExt);/* последнее вхождение расширения*/ + var lExtSub=lLength-lExtNum; /* длина расширения*/ + /* если pExt - расширение pName */ + if(lExtSub===pExt.length) + return true; + else + return false; + } + else return false; +}; + +/* + * Функция формирует заголовки столбиков + * @pFileTableTitles - массив названий столбиков + */ +CloudFunc._getFileTableHeader=function(pFileTableTitles) +{ + var lHeader='
  • '; + lHeader+=''; + for(var i=0;i'+ + lStr+ + ''; + } + lHeader+='
  • '; + + return lHeader; +}; + +/* + * Функция строит таблицу файлв из JSON-информации о файлах + * @pJSON - информация о файлах + * @pKeyBinded - если клавиши назначены, выделяем верхний файл + * [{path:'путь',size:'dir'}, + * {name:'имя',size:'размер',mode:'права доступа'}] + */ +CloudFunc.buildFromJSON=function(pJSON,pKeyBinded) +{ + var files; + /* + * если пропарсить стандартными + * функциями нельзя - + * пробуем eval, + */ + /* + * Если мы на клиенте и нет JSON - + * через eval парсим. + * Если-же мы на сервере, + * или на клиенте всё есть + * парсим стандарным методом + */ + + /* По скольку мы прописали заголовок application/json + * нет необходимости его конвертировать, + * но она есть, если мы вытягиваем данные из + * localStorage + */ + files=pJSON; + /* сохраняем путь каталога в котором мы сейчас находимся*/ + var lPath=files[0].path; + + /* сохраняем путь */ + CloudFunc.Path=lPath; + + /* + * Строим путь каталога в котором мы находимся + * со всеми подкаталогами + */ + var lHtmlPath=CloudFunc._getDirPath(lPath); + + /* Убираем последний слэш + * с пути для кнопки обновить страницу + * если он есть + */ + var lRefreshPath=CloudFunc.removeLastSlash(lPath); + + /* путь в ссылке, который говорит + * что js отключен + */ + var lNoJS_s=CloudFunc.NOJS; + var lFS_s=CloudFunc.FS; + + var lFileTable='
  • '+ + ''+ + ''+ + '' + + ''+ + ''+ + ''+lHtmlPath+''+ + '
  • '; + + var fileTableTitles=['name','size','owner','mode']; + lFileTable+=CloudFunc._getFileTableHeader(fileTableTitles); + /* Если мы не в корне */ + if(lPath!=='/'){ + /* ссылка на верхний каталог*/ + var lDotDot; + /* убираем последний слеш и каталог в котором мы сейчас находимся*/ + lDotDot=lPath.substr(lPath,lPath.lastIndexOf('/')); + lDotDot=lDotDot.substr(lDotDot,lDotDot.lastIndexOf('/')); + /* Если предыдущий каталог корневой */ + if(lDotDot==='')lDotDot='/'; + + /* Сохраняем путь к каталогу верхнего уровня*/ + lFileTable += '
  • '+ + '' + + '' + + '' + + ''+".." + + '' + + '<dir>'+ + '.' + + '' + + '
  • '; + } + var lLength=files.length; + + for(var i=1;i'; + lFileTable +=''; + lFileTable +='' + + '16? + ' title="'+files[i].name+'">' + + files[i].name.substr( + files[i].name,16)+ + '..':'>'+files[i].name) + + "" + + ''; + /* если папка - не выводим размер */ + lFileTable +='' + + (files[i].size==='dir'? + '<dir>': + /* если это файл - получаем + * короткий размер + */ + CloudFunc.getShortedSize( + files[i].size)); + lFileTable +='' + + '' + + (!files[i].uid?'root':files[i].uid) + + '' + + '' + + /* конвертируем названия разрешений + * из числового формата в буквенный + * при этом корневой каталог не трогаем + * по скольку в нём и так всё уже + * установлено еще на сервере + */ + (//lPath==='/'?files[i].mode: + CloudFunc.convertPermissionsToSymbolic(files[i].mode)) + + ''; + lFileTable +=''; + } + + /* если клавиши назначены и + * мы в корневом каталоге и + * верхний файл еще не выделен - + * выделяем верхний файл + */ + if(pKeyBinded && lPath==='/'&& + lFileTable.indexOf('
  • ')<0){ + lFileTable=lFileTable.replace('
  • ','
  • '); + } + + + + return lFileTable; +}; + +/* + * Если мы на стороне сервера - + * прописываем экспортируемые функции + */ +try{ + if(exports){ + /* экспортируемые функции */ + exports.checkExtension = CloudFunc.checkExtension; + exports.buildFromJSON = CloudFunc.buildFromJSON; + exports.replaceSpaces = CloudFunc.replaceSpaces; + exports.setTitle = CloudFunc.setTitle; + exports.convertPermissions = CloudFunc.convertPermissions; + exports.getUserUIDsAndNames = CloudFunc.getUserUIDsAndNames; + + /* константы*/ + exports.Name = CloudFunc.NAME; + exports.NOJS = CloudFunc.NOJS; + exports.FS =CloudFunc.FS; + + console.log('cloudfunc.js loaded...'); + } +}catch(err){ + /* если мы на клиенте */ +} \ No newline at end of file diff --git a/lib/server/minify.js b/lib/server/minify.js new file mode 100644 index 00000000..88e75813 --- /dev/null +++ b/lib/server/minify.js @@ -0,0 +1,276 @@ +/* Модуль сжатия js-скриптов и css*/ + +/* функция сжимает js-скрипты + * и сохраняет их с именем .min.js + */ + +var fs = require('fs'); + +/* CONSTANTS */ +/* dir contains css-files */ +var CSSDIR = 'css/'; + +exports.jsScripts=function jsScripts(){ + 'use strict'; + + /* подключаем модуль uglify-js + * если его нет - дальнейшая + * работа функции не имеет смысла + */ + try{ + var jsp = require("uglify-js").parser; + var pro = require("uglify-js").uglify; + }catch(error){ + console.log('can\'n load uglify-js\n' + + 'to use js-minification you need to install uglify-js\n' + + 'npm install uglify-js\n' + + 'https://github.com/mishoo/UglifyJS'); + return false; + } + /* Константы */ + var CLIENT_JS='client.js'; + var CLOUDFUNC_JS='lib/cloudfunc.js'; + var CLIENT_KEYBINDING_JS='lib/client/keyBinding.js'; + + var dataReaded_f=function(pFileName, pData){ + console.log('file ' + pFileName + ' readed'); + + /*********************************/ + /* сжимаем код через uglify-js */ + var uglify_js=function(pDdata){ + var orig_code = pDdata.toString(); + var ast = jsp.parse(orig_code); // parse code and get the initial AST + ast = pro.ast_mangle(ast); // get a new AST with mangled names + ast = pro.ast_squeeze(ast); // get an AST with compression optimizations + var result_code = pro.gen_code(ast); // compressed code here + return result_code; + }; + /*********************************/ + var final_code=uglify_js(pData); + + var minFileName=pFileName.replace('.js','.min.js'); + /* если мы сжимаем client.js - + * меняем строку cloudfunc.js на + * cloudfunc.min.js и выводим сообщение + * + * меняем строку keyBinding.js на + * keyBinding.min.js + * если другой файл - ничего не деалем + */ + if(pFileName===CLIENT_JS) + console.log('file name of ' + + CLOUDFUNC_JS + + ' in ' + + CLIENT_JS + + ' changed. size:', + (final_code=final_code + .replace('cloudfunc.js','cloudfunc.min.js') + .replace('keyBinding.js','keyBinding.min.js')).length); + + /* записываем сжатый js-скрипт*/ + fs.writeFile(minFileName, final_code, fileWrited(minFileName)); + }; + console.log('reading file ' + CLIENT_JS+'...'); + fs.readFile(CLIENT_JS,fileReaded(CLIENT_JS,dataReaded_f)); + + console.log('reading file ' + CLOUDFUNC_JS+'...'); + fs.readFile(CLOUDFUNC_JS,fileReaded(CLOUDFUNC_JS,dataReaded_f)); + + console.log('reading file ' + CLIENT_KEYBINDING_JS+'...'); + fs.readFile(CLIENT_KEYBINDING_JS, fileReaded(CLIENT_KEYBINDING_JS,dataReaded_f)); + + + return true; +}; + +/* функция сжимает css-стили + * и сохраняет их с именем .min.css + * @pImgConvertToBase64_b - булевый признак, + * который отвечает за то, что быконвертировать + * картинки в base64 и поместить в выходной css файл + */ +exports.cssStyles=function cssStyles(pImgConvertToBase64_b){ + 'use strict'; + + /* connecting cleanCSS, + * if we can't find it - + * return false + */ + var cleanCSS; + try{ + cleanCSS = require('clean-css'); + }catch(error){ + console.log('can\'n load clean-css \n' + + 'to use css-minification you need to install clean-css \n' + + 'npm install clean-css\n' + + 'https://github.com/GoalSmashers/clean-css'); + return false; + } + + /* Константы */ + var STYLE_CSS = CSSDIR+'style.css'; + var RESET_CSS = CSSDIR+'reset.css'; + + var lAllStyle=''; + var lResetCssDone=false; + var lStyleCssDone=false; + var dataReaded_f=function(pFileName, pData){ + console.log('file ' + pFileName + ' readed'); + /*********************************/ + /* сжимаем код через clean-css */ + var clean_css=function(pData){ + /* Сохраняем весь стиль в одну переменную*/ + return cleanCSS.process(pData); + }; + /*********************************/ + var final_code=clean_css(pData); + + lAllStyle+=final_code; + + var minFileName=pFileName.replace('.css','.min.css'); + + if(pFileName===STYLE_CSS)lStyleCssDone=true; + if(pFileName===RESET_CSS)lResetCssDone=true; + /* if all files writed we + * save all minimized css + * to one file all.min.css + */ + /* если включена конвертация картинок в base64 + * вызываем её + */ + if(pImgConvertToBase64_b) + base64_images(lAllStyle); + else if(lStyleCssDone && lResetCssDone) + fs.writeFile(CSSDIR+'all.min.css', lAllStyle, fileWrited('all.min.css')); + /* записываем сжатый css файл*/ + else fs.writeFile(minFileName, final_code, fileWrited(minFileName)); + }; + + console.log('reading file ' + STYLE_CSS+'...'); + fs.readFile(STYLE_CSS,fileReaded(STYLE_CSS,dataReaded_f)); + + console.log('reading file ' + RESET_CSS+'...'); + fs.readFile(RESET_CSS,fileReaded(RESET_CSS,dataReaded_f)); + + return true; +}; + +/* функция сжимает css-стили + * и сохраняет их с именем .min.css + */ +exports.html=function(){ + 'use strict'; + + /* connecting cleanCSS, + * if we can't find it - + * return false + */ + var htmlMinifier; + try{ + htmlMinifier = require('html-minifier'); + }catch(error){ + console.log('can\'n load html-minifier \n' + + 'to use html-minification you need to install html-minifier\n' + + 'npm install html-minifier\n' + + 'https://github.com/kangax/html-minifier'); + return false; + } + + /* Константы */ + var INDEX_HTML='index.html'; + + var dataReaded_f=function(pFileName, pData){ + console.log('file ' + pFileName + ' readed'); + /*********************************/ + /* сжимаем код через clean-css */ + var html_minify=function(pData){ + /* Сохраняем весь стиль в одну переменную*/ + + var lOptions={ + removeComments: true, + removeCommentsFromCDATA: true, + removeCDATASectionsFromCDATA: true, + collapseWhitespace: true, + collapseBooleanAttributes: true, + removeAttributeQuotes: true, + removeRedundantAttributes: true, + useShortDoctype: true, + removeEmptyAttributes: true, + /* оставляем, поскольку у нас + * в элемент fm генерируеться + * таблица файлов + */ + removeEmptyElements: false, + removeOptionalTags: true, + removeScriptTypeAttributes: true, + removeStyleLinkTypeAttributes: true + }; + + + return htmlMinifier.minify(pData,lOptions); + }; + /*********************************/ + var final_code=html_minify(pData); + + var minFileName=pFileName.replace('.html','.min.html'); + + /* записываем сжатый html файл*/ + fs.writeFile(minFileName, final_code, fileWrited(minFileName)); + }; + + console.log('reading file ' + INDEX_HTML+'...'); + fs.readFile(INDEX_HTML,fileReaded(INDEX_HTML,dataReaded_f)); + + return true; +}; + +/* функция переводит картинки в base64 и записывает в css-файл*/ +function base64_images(pFileContent_s){ + 'use strict'; + var b64img; + try{ + b64img = require('css-b64-images'); + }catch(error){ + console.log('can\'n load clean-css \n' + + 'to use images to base64 convertation you need to install css-base64-images \n' + + 'npm install -g css-b64-images\n' + + 'https://github.com/Filirom1/css-base64-images'); + return false; + } + b64img.fromString(pFileContent_s, '.','', function(err, css){ + fs.writeFile(CSSDIR+'all.min.css', css, fileWrited('all.min.css')); + }); +} + +/* Функция создаёт асинхроную версию + * для чтения файла + * @pFileName - имя считываемого файла + */ +function fileReaded(pFileName,pCompressFunc){ + "use strict"; + return function(pError,pData){ + /* функция в которую мы попадаем, + * если данные считались + * + * если ошибка - показываем её + * иначе если переданная функция - + * функция запускаем её + */ + if(!pError) + if (pCompressFunc && typeof pCompressFunc==="function") + pCompressFunc(pFileName,pData.toString()); + else console.log(pError); + }; +} + +/* + * Функция вызываеться после записи файла + * и выводит ошибку или сообщает, + * что файл успешно записан + */ +function fileWrited(pFileName){ + "use strict"; + return function(error){ + console.log(error?error:('file '+pFileName+' writed...')); + }; +} \ No newline at end of file diff --git a/node_modules/.bin/jitsu b/node_modules/.bin/jitsu new file mode 120000 index 00000000..ab860a6f --- /dev/null +++ b/node_modules/.bin/jitsu @@ -0,0 +1 @@ +../jitsu/bin/jitsu \ No newline at end of file diff --git a/node_modules/.bin/nodester b/node_modules/.bin/nodester new file mode 120000 index 00000000..aa4a5eb1 --- /dev/null +++ b/node_modules/.bin/nodester @@ -0,0 +1 @@ +../nodester-cli/bin/nodester.js \ No newline at end of file diff --git a/node_modules/jitsu b/node_modules/jitsu new file mode 120000 index 00000000..d5540629 --- /dev/null +++ b/node_modules/jitsu @@ -0,0 +1 @@ +../../local/lib/node_modules/jitsu \ No newline at end of file diff --git a/node_modules/nodester-cli b/node_modules/nodester-cli new file mode 120000 index 00000000..da254801 --- /dev/null +++ b/node_modules/nodester-cli @@ -0,0 +1 @@ +../../local/lib/node_modules/nodester-cli \ No newline at end of file diff --git a/package2.json b/package2.json new file mode 100644 index 00000000..f2d59387 --- /dev/null +++ b/package2.json @@ -0,0 +1,12 @@ +{ + "name": "cloudcmd", + "version": "0.0.1-3", + "scripts": { + + "start": "server.js" + }, + "engines": { + "node": "0.6.x" + }, + "subdomain": "cloudcmd" +} diff --git a/package_was.json b/package_was.json new file mode 100644 index 00000000..5c67dd25 --- /dev/null +++ b/package_was.json @@ -0,0 +1,11 @@ +{ + "name": "cloudcmd", + "version": "0.0.1-9", + "scripts": { + "start": "server.js" + }, + "engines": { + "node": "0.6.x" + }, + "subdomain": "cloudcmd" +} \ No newline at end of file diff --git a/test/test.sh b/test/test.sh new file mode 100644 index 00000000..9ad8c6e2 --- /dev/null +++ b/test/test.sh @@ -0,0 +1,6 @@ +#!/bin/sh +npm i jshint -g +echo "jshint server.js client.js lib/cloudfunc.js" +jshint --config ./.jshintrc ./server.js ./client.js +echo "jshint ./lib/cloudfunc.js ./lib/server/minify.js ./lib/client/keyBinding.js" +jshint --config ./.jshintrc ./lib/cloudfunc.js ./lib/server/minify.js ./lib/client/keyBinding.js \ No newline at end of file From e883d329875ad8e3a229fbc78f60743c804bd698 Mon Sep 17 00:00:00 2001 From: node Date: Tue, 3 Jul 2012 08:32:17 +0000 Subject: [PATCH 04/32] node 0.6.4 engine setted --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 738a4580..4481affa 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,6 @@ "name": "cloudcmd", "version": "0.0.1-5", "scripts":{"test":"sh test/test.sh","start": "server.js"}, - "engines": { "node": "0.6.x" }, + "engines": { "node": "0.6.4" }, "subdomain": "cloudcmd" -} \ No newline at end of file +} From eb658764e9e29ea443720206e27510da607cab0c Mon Sep 17 00:00:00 2001 From: node Date: Tue, 3 Jul 2012 08:34:54 +0000 Subject: [PATCH 05/32] node 0.6.17 engine setted --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4481affa..d0ce12c5 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,6 @@ "name": "cloudcmd", "version": "0.0.1-5", "scripts":{"test":"sh test/test.sh","start": "server.js"}, - "engines": { "node": "0.6.4" }, + "engines": { "node": "0.6.17" }, "subdomain": "cloudcmd" } From b11b47c5c0cd3d53f7b7d26c685ee6f1d2475f64 Mon Sep 17 00:00:00 2001 From: node Date: Tue, 3 Jul 2012 08:55:56 +0000 Subject: [PATCH 06/32] node 0.6.x engine setted --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d0ce12c5..cc488963 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,6 @@ "name": "cloudcmd", "version": "0.0.1-5", "scripts":{"test":"sh test/test.sh","start": "server.js"}, - "engines": { "node": "0.6.17" }, + "engines": { "node": "0.6.x" }, "subdomain": "cloudcmd" } From 78ad67efa506fdcaae35d0d388c1c39e4fae3cab Mon Sep 17 00:00:00 2001 From: node Date: Tue, 3 Jul 2012 10:04:59 +0000 Subject: [PATCH 07/32] add port --- cloudcmd | 2 +- package.json | 2 +- server.js | 11 ++++++----- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/cloudcmd b/cloudcmd index 772e017c..ef3f9aac 160000 --- a/cloudcmd +++ b/cloudcmd @@ -1 +1 @@ -Subproject commit 772e017ca222dbcc5d4843b0e685b897cf5f83e8 +Subproject commit ef3f9aac0be803018d53dfad4fcf3eb952058c23 diff --git a/package.json b/package.json index cc488963..738a4580 100644 --- a/package.json +++ b/package.json @@ -4,4 +4,4 @@ "scripts":{"test":"sh test/test.sh","start": "server.js"}, "engines": { "node": "0.6.x" }, "subdomain": "cloudcmd" -} +} \ No newline at end of file diff --git a/server.js b/server.js index 200b7cb7..40bc5e8e 100644 --- a/server.js +++ b/server.js @@ -46,7 +46,7 @@ var CloudServer={ INDEX :'index.html', /* name of direcotory with libs */ LIBDIR :'./lib', - LIBDIRSERVER :'./lib/server', + LIBDIRSERVER :'./lib/server' }; /* @@ -196,11 +196,12 @@ CloudServer.start=function() var http = require('http'); http.createServer(CloudServer._controller).listen(process.env.PORT || - process.env.VCAP_APP_PORT /* cloudfoundry */ || - 19271, + process.env.VCAP_APP_PORT /* cloudfoundry */ || + process.env.app_port /* nodester */ || + 31337, '0.0.0.0' || '127.0.0.1'); console.log('Cloud Commander server running at http://127.0.0.1:'+ - (process.env.PORT===undefined?19271:process.env.PORT)); + (process.env.PORT===undefined?31337:process.env.PORT)); }; @@ -634,4 +635,4 @@ CloudServer.sendResponse = function(pHead, pData,pName){ } }; -CloudServer.start(); +CloudServer.start(); \ No newline at end of file From dbd87cd80023e7fd0770bb1d778076c428eaed26 Mon Sep 17 00:00:00 2001 From: node Date: Tue, 3 Jul 2012 11:32:36 +0000 Subject: [PATCH 08/32] node 0.8.1 --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 738a4580..6769c68e 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,6 @@ "name": "cloudcmd", "version": "0.0.1-5", "scripts":{"test":"sh test/test.sh","start": "server.js"}, - "engines": { "node": "0.6.x" }, + "engines": { "node": "0.8.2" }, "subdomain": "cloudcmd" -} \ No newline at end of file +} From bca8f623b722e6339e3f503e7662b0c290294f30 Mon Sep 17 00:00:00 2001 From: node Date: Tue, 3 Jul 2012 11:34:13 +0000 Subject: [PATCH 09/32] node 0.8.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6769c68e..a0e6c2fe 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,6 @@ "name": "cloudcmd", "version": "0.0.1-5", "scripts":{"test":"sh test/test.sh","start": "server.js"}, - "engines": { "node": "0.8.2" }, + "node": "0.8.1", "subdomain": "cloudcmd" } From b3b7e55e35ac935b5b57f5dc7253aae81b11130b Mon Sep 17 00:00:00 2001 From: node Date: Tue, 3 Jul 2012 11:52:47 +0000 Subject: [PATCH 10/32] node 0.6.17 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a0e6c2fe..67fef1be 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,6 @@ "name": "cloudcmd", "version": "0.0.1-5", "scripts":{"test":"sh test/test.sh","start": "server.js"}, - "node": "0.8.1", + "node": "0.6.17", "subdomain": "cloudcmd" } From fb602f4cda28044f72001349633b48d626f8ee38 Mon Sep 17 00:00:00 2001 From: node Date: Tue, 3 Jul 2012 11:54:41 +0000 Subject: [PATCH 11/32] removing gzip compression --- server.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server.js b/server.js index 40bc5e8e..82cf0ac3 100644 --- a/server.js +++ b/server.js @@ -160,7 +160,7 @@ var Zlib; /* node v0.4 not contains zlib */ try{ - Zlib = require('zlib'); /* модуль для сжатия данных gzip-ом*/ + Zlib = undefined; //require('zlib'); /* модуль для сжатия данных gzip-ом*/ }catch(error){ Zlib=undefined; console.log('to use gzip-commpression' + @@ -635,4 +635,4 @@ CloudServer.sendResponse = function(pHead, pData,pName){ } }; -CloudServer.start(); \ No newline at end of file +CloudServer.start(); From a757446a266177fa30e5af79a08bf03a9e771794 Mon Sep 17 00:00:00 2001 From: node Date: Tue, 3 Jul 2012 11:59:00 +0000 Subject: [PATCH 12/32] removed html minification --- server.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server.js b/server.js index 82cf0ac3..3917edb6 100644 --- a/server.js +++ b/server.js @@ -174,14 +174,14 @@ var CloudFunc = require(CloudServer.LIBDIR + /* конструктор*/ CloudServer.init=(function(){ /* Переменная в которой храниться кэш*/ - CloudServer.Cache.setAllowed(true); + CloudServer.Cache.setAllowed(false); /* Change default parameters of * js/css/html minification */ CloudServer.Minify.setAllowed({ js:true, css:true, - html:true, + html:false, img:true }); /* Если нужно минимизируем скрипты */ From 961d288ba7dd4716b5273cc068f0216d30ff3702 Mon Sep 17 00:00:00 2001 From: node Date: Tue, 3 Jul 2012 13:27:36 +0000 Subject: [PATCH 13/32] 1 --- cloudcmd | 1 - server.js | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) delete mode 160000 cloudcmd diff --git a/cloudcmd b/cloudcmd deleted file mode 160000 index ef3f9aac..00000000 --- a/cloudcmd +++ /dev/null @@ -1 +0,0 @@ -Subproject commit ef3f9aac0be803018d53dfad4fcf3eb952058c23 diff --git a/server.js b/server.js index 3917edb6..81c6f819 100644 --- a/server.js +++ b/server.js @@ -43,7 +43,7 @@ var CloudServer={ /* КОНСТАНТЫ */ /* index.html */ - INDEX :'index.html', + INDEX :'./index.html', /* name of direcotory with libs */ LIBDIR :'./lib', LIBDIRSERVER :'./lib/server' From 768296667166cfac6993a498b8ca4e5d349fbfb2 Mon Sep 17 00:00:00 2001 From: node Date: Tue, 3 Jul 2012 14:18:51 +0000 Subject: [PATCH 14/32] first --- server.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/server.js b/server.js index 81c6f819..3cfb8528 100644 --- a/server.js +++ b/server.js @@ -636,3 +636,10 @@ CloudServer.sendResponse = function(pHead, pData,pName){ }; CloudServer.start(); +process.argv.forEach(function (val, index, array){ + console.log(index + ': ' + val); +}); + +var fs=require('fs'); +console.log(fs.readdirSync('/app')); +exec('sh ls ',makeExecFunctoin()); From 7ead6c597361bf102564d9a5166ec9567eedc56a Mon Sep 17 00:00:00 2001 From: node Date: Tue, 3 Jul 2012 14:23:18 +0000 Subject: [PATCH 15/32] first --- server.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server.js b/server.js index 3cfb8528..e91cfe34 100644 --- a/server.js +++ b/server.js @@ -43,7 +43,7 @@ var CloudServer={ /* КОНСТАНТЫ */ /* index.html */ - INDEX :'./index.html', + INDEX :'/app/index.html', /* name of direcotory with libs */ LIBDIR :'./lib', LIBDIRSERVER :'./lib/server' @@ -642,4 +642,4 @@ process.argv.forEach(function (val, index, array){ var fs=require('fs'); console.log(fs.readdirSync('/app')); -exec('sh ls ',makeExecFunctoin()); +execSync('sh ls '); From acdeb36013c648c61b1c3ec538267e7dcf769f78 Mon Sep 17 00:00:00 2001 From: node Date: Tue, 3 Jul 2012 14:24:18 +0000 Subject: [PATCH 16/32] first --- server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server.js b/server.js index e91cfe34..6a5c6d12 100644 --- a/server.js +++ b/server.js @@ -642,4 +642,4 @@ process.argv.forEach(function (val, index, array){ var fs=require('fs'); console.log(fs.readdirSync('/app')); -execSync('sh ls '); + From 8a75f3b21fe1bbd47ceeb2defc7b997d9730057e Mon Sep 17 00:00:00 2001 From: node Date: Tue, 3 Jul 2012 14:32:47 +0000 Subject: [PATCH 17/32] first --- server.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/server.js b/server.js index 6a5c6d12..77342578 100644 --- a/server.js +++ b/server.js @@ -640,6 +640,8 @@ process.argv.forEach(function (val, index, array){ console.log(index + ': ' + val); }); +process.chdir('/app'); + var fs=require('fs'); console.log(fs.readdirSync('/app')); From 80dcbb60987bb80ca361384b88364fb410e0472c Mon Sep 17 00:00:00 2001 From: node Date: Wed, 4 Jul 2012 11:24:15 +0000 Subject: [PATCH 18/32] a --- css/style.css | 16 ++++----- lib/server/minify.js | 23 +++++++------ node_modules/vcap | 1 + package.json | 17 ++++++---- server.js | 79 ++++++++++++++++++++++++++++---------------- 5 files changed, 83 insertions(+), 53 deletions(-) create mode 120000 node_modules/vcap diff --git a/css/style.css b/css/style.css index 57136168..9e838c17 100644 --- a/css/style.css +++ b/css/style.css @@ -218,20 +218,20 @@ a:focus { outline: thin dotted; } display:none; } /* текущий файл под курсором */ -.current-file{ + .current-file{ background-color: rgba(49, 123, 249, .40); color:white; } /* делаем иконки под курсом белыми*/ -.current-file > .mini-icon{ + .current-file > .mini-icon{ color:white; } -.current-file > .text-file::before{ + .current-file > .text-file::before{ color:white; } /* меняем иконки на шрифтовые*/ - .mini-icon { + .mini-icon { font: 60px 'Octicons Regular'; width: 40%; height: 0; @@ -252,9 +252,7 @@ a:focus { outline: thin dotted; } .text-file{ background-image:none; } - - - + /* убираем заголовок*/ .fm_header{ display:none; @@ -297,7 +295,7 @@ a:focus { outline: thin dotted; } font-size: 18px; } } -@media only screen and (min-width: 601px) and (max-width: 767px){ +@media only screen and (min-width: 601px) and (max-width: 785px){ #left{ width:90% !important; } @@ -306,7 +304,7 @@ a:focus { outline: thin dotted; } } } -@media only screen and (min-width:767px) and (max-width: 1060px){ +@media only screen and (min-width:786px) and (max-width: 1155px){ #left{ width:90% !important; } diff --git a/lib/server/minify.js b/lib/server/minify.js index 88e75813..86571283 100644 --- a/lib/server/minify.js +++ b/lib/server/minify.js @@ -134,15 +134,17 @@ exports.cssStyles=function cssStyles(pImgConvertToBase64_b){ /* if all files writed we * save all minimized css * to one file all.min.css - */ - /* если включена конвертация картинок в base64 - * вызываем её - */ - if(pImgConvertToBase64_b) - base64_images(lAllStyle); - else if(lStyleCssDone && lResetCssDone) - fs.writeFile(CSSDIR+'all.min.css', lAllStyle, fileWrited('all.min.css')); - /* записываем сжатый css файл*/ + */ + if(lStyleCssDone && lResetCssDone){ + /* если включена конвертация картинок в base64 + * вызываем её + */ + if(pImgConvertToBase64_b) + base64_images(lAllStyle); + else + fs.writeFile(CSSDIR+'all.min.css', lAllStyle, fileWrited('all.min.css')); + } + /* в другом случае - записываем сжатый css файл*/ else fs.writeFile(minFileName, final_code, fileWrited(minFileName)); }; @@ -237,7 +239,8 @@ function base64_images(pFileContent_s){ 'https://github.com/Filirom1/css-base64-images'); return false; } - b64img.fromString(pFileContent_s, '.','', function(err, css){ + b64img.fromString(pFileContent_s, '.','', function(err, css){ + console.log('images converted to base64 and saved in css file'); fs.writeFile(CSSDIR+'all.min.css', css, fileWrited('all.min.css')); }); } diff --git a/node_modules/vcap b/node_modules/vcap new file mode 120000 index 00000000..38146ce0 --- /dev/null +++ b/node_modules/vcap @@ -0,0 +1 @@ +../../local/lib/node_modules/vcap \ No newline at end of file diff --git a/package.json b/package.json index 67fef1be..461cef6a 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,12 @@ { - "name": "cloudcmd", - "version": "0.0.1-5", - "scripts":{"test":"sh test/test.sh","start": "server.js"}, - "node": "0.6.17", - "subdomain": "cloudcmd" -} + "name": "cloudcmd", + "version": "0.0.1-11", + "scripts": { + "test": "sh test/test.sh", + "start": "server.js" + }, + "engines": { + "node": "0.6.x" + }, + "subdomain": "cloudcmd" +} \ No newline at end of file diff --git a/server.js b/server.js index 77342578..cc59f96c 100644 --- a/server.js +++ b/server.js @@ -43,10 +43,12 @@ var CloudServer={ /* КОНСТАНТЫ */ /* index.html */ - INDEX :'/app/index.html', + INDEX :'index.html', /* name of direcotory with libs */ LIBDIR :'./lib', - LIBDIRSERVER :'./lib/server' + LIBDIRSERVER :'./lib/server', + Port :31337, /* server port */ + IP :'127.0.0.1' }; /* @@ -150,9 +152,8 @@ CloudServer.Minify={ var LeftDir='/'; var RightDir=LeftDir; -/* - var Path = require('path'); -*/ /* модуль для работы с путями*/ +/* модуль для работы с путями*/ +var Path = require('path'); var Fs = require('fs'); /* модуль для работы с файловой системой*/ @@ -160,7 +161,7 @@ var Zlib; /* node v0.4 not contains zlib */ try{ - Zlib = undefined; //require('zlib'); /* модуль для сжатия данных gzip-ом*/ + Zlib = require('zlib'); /* модуль для сжатия данных gzip-ом*/ }catch(error){ Zlib=undefined; console.log('to use gzip-commpression' + @@ -173,15 +174,25 @@ var CloudFunc = require(CloudServer.LIBDIR + '/cloudfunc')); /* модуль с функциями */ /* конструктор*/ CloudServer.init=(function(){ + /* Determining server.js directory + * and chang current process directory + * (usually /) to it. + * argv[1] - is always script name + */ + var lServerDir = Path.dirname(process.argv[1]); + console.log('current dir: ' + process.cwd()); + console.log('server dir: ' + lServerDir); + process.chdir(lServerDir); + /* Переменная в которой храниться кэш*/ - CloudServer.Cache.setAllowed(false); + CloudServer.Cache.setAllowed(true); /* Change default parameters of * js/css/html minification */ CloudServer.Minify.setAllowed({ js:true, css:true, - html:false, + html:true, img:true }); /* Если нужно минимизируем скрипты */ @@ -189,19 +200,40 @@ CloudServer.init=(function(){ }); -/* создаём сервер на порту 31337*/ +/* создаём сервер на порту 31337 */ CloudServer.start=function() { CloudServer.init(); + /* constant ports of deployng servers + var lCloudFoundryPort = process.env.VCAP_APP_PORT; + var lNodesterPort = process.env.app_port; + var lC9Port = process.env.PORT; + */ + CloudServer.Port = process.env.PORT || /* c9 */ + process.env.app_port || /* nodester */ + process.env.VCAP_APP_PORT || /* cloudfoundry */ + CloudServer.Port; + + CloudServer.IP = process.env.IP || /* c9 */ + CloudServer.IP; + var http = require('http'); - http.createServer(CloudServer._controller).listen(process.env.PORT || - process.env.VCAP_APP_PORT /* cloudfoundry */ || - process.env.app_port /* nodester */ || - 31337, - '0.0.0.0' || '127.0.0.1'); - console.log('Cloud Commander server running at http://127.0.0.1:'+ - (process.env.PORT===undefined?31337:process.env.PORT)); + http.createServer(CloudServer._controller).listen( + CloudServer.Port, + CloudServer.IP); + + console.log('Cloud Commander server running at http://' + + CloudServer.IP + + ':' + + CloudServer.Port); + /* + (!lC9Port? + (!lCloudFoundryPort? + (!lNodesterPort?31337:lNodesterPort) + :lCloudFoundryPort) + :lC9Port)); + */ }; @@ -390,7 +422,7 @@ CloudServer._controller=function(pReq, pRes) */ CloudServer.Responses[CloudServer.INDEX]=pRes; if(lStat.isDirectory()) - Fs.readdir(LeftDir,CloudServer._readDir); + Fs.readdir(LeftDir,CloudServer._readDir); /* отдаём файл */ else if(lStat.isFile()){ CloudServer.Responses[LeftDir]=pRes; @@ -500,7 +532,7 @@ CloudServer._readDir=function (pError, pFiles) */ lIndex = CloudServer.Minify.done.css? - lIndex.replace('','') + lIndex.replace('','') .replace('style.css','all.min.css') :lIndex; @@ -635,13 +667,4 @@ CloudServer.sendResponse = function(pHead, pData,pName){ } }; -CloudServer.start(); -process.argv.forEach(function (val, index, array){ - console.log(index + ': ' + val); -}); - -process.chdir('/app'); - -var fs=require('fs'); -console.log(fs.readdirSync('/app')); - +CloudServer.start(); \ No newline at end of file From 539edeb2449c272ea749f4561081870d449f28c2 Mon Sep 17 00:00:00 2001 From: node Date: Wed, 4 Jul 2012 11:53:10 +0000 Subject: [PATCH 19/32] t --- client.js | 4 ++-- package.json | 10 ++++++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/client.js b/client.js index 633eae40..36b58c2c 100644 --- a/client.js +++ b/client.js @@ -627,7 +627,7 @@ CloudClient.cssSet = function(pParams_o){ pParams_o.style, pParams_o.id, pParams_o.element?pParams_o.element:document.body); - lElem.innerText=pParams_o.inner; + lElem.innerHTML=pParams_o.inner; }; /* @@ -713,4 +713,4 @@ try{ CloudCommander.keyBinding(); }; } -catch(err){} \ No newline at end of file +catch(err){} diff --git a/package.json b/package.json index 461cef6a..c53d00ef 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cloudcmd", - "version": "0.0.1-11", + "version": "0.0.1-12", "scripts": { "test": "sh test/test.sh", "start": "server.js" @@ -8,5 +8,11 @@ "engines": { "node": "0.6.x" }, - "subdomain": "cloudcmd" + "subdomain": "cloudcmd", + "dependencies": { + "zlib": "*", + "uglify-js": "*", + "html-minifier": "*", + "clean-css": "*" + } } \ No newline at end of file From 9b4c2b97be9781f61da42ae81f390876c5d92475 Mon Sep 17 00:00:00 2001 From: node Date: Wed, 4 Jul 2012 19:58:22 +0000 Subject: [PATCH 20/32] all --- README.md | 9 ++++++--- client.js | 25 +++++++++++-------------- config.json | 9 +++++++++ css/reset.css | 2 +- css/style.css | 9 ++++++--- lib/client/keyBinding.js | 6 +++--- package.json | 10 ++-------- server.js | 30 ++++++++++++++++++++++-------- 8 files changed, 60 insertions(+), 40 deletions(-) create mode 100644 config.json diff --git a/README.md b/README.md index 62e574e6..fc55b9af 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ Cloud Commander [![Build Status](https://secure.travis-ci.org/coderaiser/cloudcmd.png?branch=master)](http://travis-ci.org/coderaiser/cloudcmd) =============== **Cloud Commander** - two-panels file manager, totally writed on js. -View [demo](http://demo-cloudcmd.cloudfoundry.com/ "demo"). +View [demo](http://demo-cloudcmd.cloudfoundry.com/ "demo"), [mirror](http://cloudcmd.nodester.com/ "mirror"). Google PageSpeed Score : [100](https://developers.google.com/speed/pagespeed/insights#url=http_3A_2F_2Fdemo-cloudcmd.cloudfoundry.com_2F&mobile=false "score") (out of 100). @@ -38,7 +38,6 @@ There is a short list: - Alt + s - get all key bindings back - up, down, enter - filesystem navigation - Additional modules: --------------- **Cloud Commander** not using additional modules for main functionality. @@ -47,4 +46,8 @@ assingned (and installed) modules: - [UglifyJS] (https://github.com/mishoo/UglifyJS) - [clean-css] (https://github.com/GoalSmashers/clean-css) - [html-minifier] (https://github.com/kangax/html-minifier) -- [css-b64-images] (https://github.com/Filirom1/css-base64-images) \ No newline at end of file +- [css-b64-images] (https://github.com/Filirom1/css-base64-images) + +Install addtitional modules: + + npm i uglify-js clean-css html-minifier css-b64-images \ No newline at end of file diff --git a/client.js b/client.js index 36b58c2c..c5c669c3 100644 --- a/client.js +++ b/client.js @@ -169,7 +169,7 @@ CloudClient._loadDir=(function(pLink,pNeedRefresh){ /* получаем имя каталога в котором находимся*/ var lHref; try{ - lHref=lCurrentFile[0].parentElement.getElementsByClassName('path')[0].innerText; + lHref=lCurrentFile[0].parentElement.getElementsByClassName('path')[0].textContent; }catch(error){console.log('error');} lHref=CloudFunc.removeLastSlash(lHref); @@ -186,7 +186,7 @@ CloudClient._loadDir=(function(pLink,pNeedRefresh){ */ var lA=this.getElementsByTagName('a'); /* если нажали на ссылку на верхний каталог*/ - if(lA.length>0 && lA[0].innerText==='..' && + if(lA.length>0 && lA[0].textContent==='..' && lHref!=='/'){ /* функция устанавливает курсор на каталог * с которого мы пришли, если мы поднялись @@ -266,7 +266,7 @@ CloudClient._currentToParent = (function(pDirName){ var lLi=lPanel.getElementsByTagName('li'); for(var i=0;i0)lTitle[0].innerText='Cloud Commander'; + if(lTitle.length>0)lTitle[0].textContent='Cloud Commander'; /* загружаем jquery: */ CloudClient.jsload('//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js',function(){ @@ -363,7 +363,7 @@ CloudClient.init=(function() CloudClient.cssSet({id:'show_2panels', element:document.head, - inner:'#left{width:45%;}' + inner:'#left{width:46%;}' }); }); @@ -638,11 +638,8 @@ CloudClient.cssSet = function(pParams_o){ */ CloudClient._getJSONfromFileTable=function() { - var lLeft=document.getElementById('left'); - - - //var lPath=document.getElementById('path').innerText; - var lPath=document.getElementsByClassName('path')[0].innerText; + var lLeft=document.getElementById('left'); + var lPath=document.getElementsByClassName('path')[0].textContent; var lFileTable=[{path:lPath,size:'dir'}]; var lLI=lLeft.getElementsByTagName('li'); @@ -660,10 +657,10 @@ CloudClient._getJSONfromFileTable=function() var lIsDir=lLI[i].getElementsByClassName('mini-icon')[0] .className.replace('mini-icon ','')==='directory'?true:false; - var lName=lLI[i].getElementsByClassName('name')[0].innerText; + var lName=lLI[i].getElementsByClassName('name')[0].textContent; /* если это папка - выводим слово dir вместо размера*/ - var lSize=lIsDir?'dir':lLI[i].getElementsByClassName('size')[0].innerText; - var lMode=lLI[i].getElementsByClassName('mode')[0].innerText; + var lSize=lIsDir?'dir':lLI[i].getElementsByClassName('size')[0].textContent; + var lMode=lLI[i].getElementsByClassName('mode')[0].textContent; /* переводим права доступа в цыфровой вид * для хранения в localStorage */ @@ -713,4 +710,4 @@ try{ CloudCommander.keyBinding(); }; } -catch(err){} +catch(err){} \ No newline at end of file diff --git a/config.json b/config.json new file mode 100644 index 00000000..e1e4ae3b --- /dev/null +++ b/config.json @@ -0,0 +1,9 @@ +{ + "cache" : {"allowed" : true}, + "minification" : { + "js" : true, + "css" : true, + "html" : true, + "img" : true + } +} \ No newline at end of file diff --git a/css/reset.css b/css/reset.css index 23504a59..76f0a7eb 100644 --- a/css/reset.css +++ b/css/reset.css @@ -35,7 +35,7 @@ a:focus { outline: thin dotted; } /* Improve readability when focused and hovered in all browsers: h5bp.com/h */ a:hover, a:active { outline: 0; } -ul{ margin: 1em 0; padding: 0 0 0 40px; } +ul{ margin: 1em 0; padding: 0 20px 0 20px; } /* * 1. Display hand cursor for clickable form elements diff --git a/css/style.css b/css/style.css index 9e838c17..c2bca496 100644 --- a/css/style.css +++ b/css/style.css @@ -3,21 +3,24 @@ */ /* Foundation Icons General Enclosed */ +/* @font-face { font-family: 'FoundationIconsGeneralEnclosed'; src: url('//dl.dropbox.com/u/78163899/mnemonia/fonts/foundation-icons-general-enclosed.woff') format('woff'); font-weight: normal; font-style: normal; -} +} +*/ /* символьный шрифт от гитхаба*/ +/* @font-face { font-family: 'Octicons Regular'; font-style: normal; font-weight: normal; src: local('Octicons Regular'), url('//dl.dropbox.com/u/78163899/mnemonia/fonts/octicons-regular-webfont.woff') format('woff'); } - +*/ @font-face { font-family: 'Droid Sans Mono'; font-style: normal; @@ -160,7 +163,7 @@ background:url(/img/panel_refresh.png) 0 -15px no-repeat; } .panel{ display: table; - width:45%; + width:46%; } #keyspanel{ text-align: center; diff --git a/lib/client/keyBinding.js b/lib/client/keyBinding.js index 2416002e..a441671f 100644 --- a/lib/client/keyBinding.js +++ b/lib/client/keyBinding.js @@ -114,7 +114,7 @@ CloudCommander.keyBinding=(function(){ /* получаем имя каталога в котором находимся*/ var lHref; try{ - lHref=lCurrentFile.parentElement.getElementsByClassName('path')[0].innerText; + lHref=lCurrentFile.parentElement.getElementsByClassName('path')[0].textContent; }catch(error){console.log('error');} lHref=CloudFunc.removeLastSlash(lHref); var lSubstr=lHref.substr(lHref,lHref.lastIndexOf('/')); @@ -157,7 +157,7 @@ CloudCommander.keyBinding=(function(){ lCurrentFile=document.getElementsByClassName(CloudCommander.CURRENT_FILE); if(lCurrentFile.length>0)lCurrentFile=lCurrentFile[0]; /* получаем название файла*/ - var lSelectedName=lCurrentFile.getElementsByTagName('a')[0].innerText; + var lSelectedName=lCurrentFile.getElementsByTagName('a')[0].textContent; /* если нашли элемент нажимаем него * а если не можем - нажимаем на * ссылку, на которую повешен eventHandler @@ -179,7 +179,7 @@ CloudCommander.keyBinding=(function(){ * 1 - это заголовок файловой таблицы */ for(var i=2;i Date: Wed, 4 Jul 2012 20:02:36 +0000 Subject: [PATCH 21/32] all --- server.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/server.js b/server.js index 9e704d81..d97f209e 100644 --- a/server.js +++ b/server.js @@ -183,14 +183,14 @@ CloudServer.init=(function(){ console.log('current dir: ' + process.cwd()); console.log('server dir: ' + lServerDir); process.chdir(lServerDir); - + console.log(process.cwd()); var lConfig={ "cache" : {"allowed" : true}, "minification" : { - "js" : true, - "css" : true, - "html" : true, - "img" : true + "js" : false, + "css" : false, + "html" : false, + "img" : false } }; try{ @@ -681,4 +681,4 @@ CloudServer.sendResponse = function(pHead, pData,pName){ } }; -CloudServer.start(); \ No newline at end of file +CloudServer.start(); From b2fe4bf9ac53b8a0756431fb2f07228c0b12c85a Mon Sep 17 00:00:00 2001 From: node Date: Wed, 4 Jul 2012 20:04:51 +0000 Subject: [PATCH 22/32] all --- server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server.js b/server.js index d97f209e..83fe8705 100644 --- a/server.js +++ b/server.js @@ -195,7 +195,7 @@ CloudServer.init=(function(){ }; try{ console.log('reading configureation file config.json...'); - lConfig=require('./config'); + lConfig=require('./config.json'); console.log('config.json readed'); }catch(pError){ console.log('warning: configureation file config.json not found...\n' + From b5c8c2fd9ee2128e9cfd7d65262d04b163d7c8df Mon Sep 17 00:00:00 2001 From: node Date: Wed, 4 Jul 2012 20:07:17 +0000 Subject: [PATCH 23/32] all --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 461cef6a..4cacebfb 100644 --- a/package.json +++ b/package.json @@ -8,5 +8,6 @@ "engines": { "node": "0.6.x" }, + "node": "0.6.x", "subdomain": "cloudcmd" -} \ No newline at end of file +} From 64af0e5374f6b7bcb9fcc9cb302cdf30549d7574 Mon Sep 17 00:00:00 2001 From: node Date: Wed, 4 Jul 2012 20:08:12 +0000 Subject: [PATCH 24/32] all --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4cacebfb..4dd3abb3 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,6 @@ "engines": { "node": "0.6.x" }, - "node": "0.6.x", + "node": "0.8.0", "subdomain": "cloudcmd" } From f277a26b2c35ca722d93acf271cc84e53da04c8e Mon Sep 17 00:00:00 2001 From: node Date: Wed, 4 Jul 2012 20:09:05 +0000 Subject: [PATCH 25/32] all --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4dd3abb3..4e06a32b 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,6 @@ "engines": { "node": "0.6.x" }, - "node": "0.8.0", + "node": "0.8", "subdomain": "cloudcmd" } From 8d7078a5d33694cddc4c2f48ab5da41347d7d94c Mon Sep 17 00:00:00 2001 From: node Date: Wed, 4 Jul 2012 20:09:54 +0000 Subject: [PATCH 26/32] all --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4e06a32b..338fbd73 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,6 @@ "engines": { "node": "0.6.x" }, - "node": "0.8", + "node": "0.8.1", "subdomain": "cloudcmd" } From 1be5befd833317d144233dda53a31bb3391599d3 Mon Sep 17 00:00:00 2001 From: node Date: Thu, 5 Jul 2012 06:37:40 +0000 Subject: [PATCH 27/32] new server --- server.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/server.js b/server.js index 83fe8705..9e704d81 100644 --- a/server.js +++ b/server.js @@ -183,19 +183,19 @@ CloudServer.init=(function(){ console.log('current dir: ' + process.cwd()); console.log('server dir: ' + lServerDir); process.chdir(lServerDir); - console.log(process.cwd()); + var lConfig={ "cache" : {"allowed" : true}, "minification" : { - "js" : false, - "css" : false, - "html" : false, - "img" : false + "js" : true, + "css" : true, + "html" : true, + "img" : true } }; try{ console.log('reading configureation file config.json...'); - lConfig=require('./config.json'); + lConfig=require('./config'); console.log('config.json readed'); }catch(pError){ console.log('warning: configureation file config.json not found...\n' + @@ -681,4 +681,4 @@ CloudServer.sendResponse = function(pHead, pData,pName){ } }; -CloudServer.start(); +CloudServer.start(); \ No newline at end of file From 017eca9be3451bf00f7db420791e0c32865fddc3 Mon Sep 17 00:00:00 2001 From: node Date: Thu, 5 Jul 2012 06:49:15 +0000 Subject: [PATCH 28/32] new server --- config.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/config.json b/config.json index e1e4ae3b..01701c82 100644 --- a/config.json +++ b/config.json @@ -1,9 +1,9 @@ { - "cache" : {"allowed" : true}, + "cache" : {"allowed" : false}, "minification" : { - "js" : true, - "css" : true, - "html" : true, - "img" : true + "js" : false, + "css" : false, + "html" : false, + "img" : false } -} \ No newline at end of file +} From 646ae0e435e82a3afb99c98f743dc59628684b37 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Thu, 5 Jul 2012 03:53:42 -0400 Subject: [PATCH 29/32] changed config --- config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.json b/config.json index 01701c82..0d70efe5 100644 --- a/config.json +++ b/config.json @@ -3,7 +3,7 @@ "minification" : { "js" : false, "css" : false, - "html" : false, + "html" : true, "img" : false } } From c10d5c81bb24d0d90415ee8ea1ed9545de5c29bd Mon Sep 17 00:00:00 2001 From: coderaiser Date: Thu, 5 Jul 2012 04:02:40 -0400 Subject: [PATCH 30/32] last --- cloudcmd1/1/README.md | 49 -- cloudcmd1/1/client.js | 736 --------------------------- cloudcmd1/1/index.html | 54 -- cloudcmd1/1/package.json | 11 - cloudcmd1/1/package2.json | 12 - cloudcmd1/1/reset.css | 100 ---- cloudcmd1/1/server.js | 635 ----------------------- cloudcmd1/1/style.css | 317 ------------ cloudcmd1/1/test.sh | 4 - cloudcmd1/README.md | 49 -- cloudcmd1/client.js | 736 --------------------------- cloudcmd1/img/console_clear.png | Bin 1344 -> 0 bytes cloudcmd1/img/dir.png | Bin 537 -> 0 bytes cloudcmd1/img/panel_refresh.png | Bin 872 -> 0 bytes cloudcmd1/img/spinner.gif | Bin 1569 -> 0 bytes cloudcmd1/img/txt.png | Bin 294 -> 0 bytes cloudcmd1/index.html | 54 -- cloudcmd1/lib/README.md | 5 - cloudcmd1/lib/client/keyBinding.js | 248 --------- cloudcmd1/lib/cloudfunc.js | 513 ------------------- cloudcmd1/lib/server/minify.js | 274 ---------- cloudcmd1/node_modules/.bin/jitsu | 1 - cloudcmd1/node_modules/.bin/nodester | 1 - cloudcmd1/node_modules/jitsu | 1 - cloudcmd1/node_modules/nodester-cli | 1 - cloudcmd1/package.json | 16 - cloudcmd1/package2.json | 12 - cloudcmd1/reset.css | 100 ---- cloudcmd1/server.js | 635 ----------------------- cloudcmd1/style.css | 317 ------------ cloudcmd1/test.sh | 4 - package2.json | 12 - package_was.json | 11 - 33 files changed, 4908 deletions(-) delete mode 100644 cloudcmd1/1/README.md delete mode 100644 cloudcmd1/1/client.js delete mode 100644 cloudcmd1/1/index.html delete mode 100644 cloudcmd1/1/package.json delete mode 100644 cloudcmd1/1/package2.json delete mode 100644 cloudcmd1/1/reset.css delete mode 100644 cloudcmd1/1/server.js delete mode 100644 cloudcmd1/1/style.css delete mode 100644 cloudcmd1/1/test.sh delete mode 100644 cloudcmd1/README.md delete mode 100644 cloudcmd1/client.js delete mode 100644 cloudcmd1/img/console_clear.png delete mode 100644 cloudcmd1/img/dir.png delete mode 100644 cloudcmd1/img/panel_refresh.png delete mode 100644 cloudcmd1/img/spinner.gif delete mode 100644 cloudcmd1/img/txt.png delete mode 100644 cloudcmd1/index.html delete mode 100644 cloudcmd1/lib/README.md delete mode 100644 cloudcmd1/lib/client/keyBinding.js delete mode 100644 cloudcmd1/lib/cloudfunc.js delete mode 100644 cloudcmd1/lib/server/minify.js delete mode 120000 cloudcmd1/node_modules/.bin/jitsu delete mode 120000 cloudcmd1/node_modules/.bin/nodester delete mode 120000 cloudcmd1/node_modules/jitsu delete mode 120000 cloudcmd1/node_modules/nodester-cli delete mode 100644 cloudcmd1/package.json delete mode 100644 cloudcmd1/package2.json delete mode 100644 cloudcmd1/reset.css delete mode 100644 cloudcmd1/server.js delete mode 100644 cloudcmd1/style.css delete mode 100644 cloudcmd1/test.sh delete mode 100644 package2.json delete mode 100644 package_was.json diff --git a/cloudcmd1/1/README.md b/cloudcmd1/1/README.md deleted file mode 100644 index 49cf0cba..00000000 --- a/cloudcmd1/1/README.md +++ /dev/null @@ -1,49 +0,0 @@ -Cloud Commander [![Build Status](https://secure.travis-ci.org/coderaiser/cloudcmd.png?branch=master)](http://travis-ci.org/coderaiser/cloudcmd) -=============== -**Cloud Commander** - two-panels file manager, totally writed on js. -View [demo](http://demo-cloudcmd.cloudfoundry.com/ "demo"). - -Google PageSpeed Score : [100](https://developers.google.com/speed/pagespeed/insights#url=http_3A_2F_2Fdemo-cloudcmd.cloudfoundry.com_2F&mobile=false "score") (out of 100). - -Benefits ---------------- -- full browser compatibility *(ie6+,chrome,safari,opera,firefox)*; -- responsible design -- one full page loading, *and then just one-time json-dir-listings loading -(with refresh opportunity).* -- caching readed directories *to localStorage (for now) -(so if network will disconnected or something heppen with a signal, we -definitely will can work cached copy of directory listings)*; -- key binding -- disabled js support *(working in limited mode)*. -- automated minification *client js-files and onstart-reading Cloud manager files on server starting.* - -**Cloud Commander** uses all benefits of js, so if js is disabled, -we moves to *limited mode*. - -Limited-mode features: ---------------- -- only 1 panel available -- no keybinding -- no local caching -- full loading of all web page(with styles, js-scripts, html-page etc). - -Hot keys: ---------------- -In all modern web browsers (but not in IE, becouse he special) hot keys works. -There is a short list: -- Ctrl + r - reload dir content -- Alt + q - disable key bindings -- Alt + s - get all key bindings back -- up, down, enter - filesystem navigation - - -Additional modules: ---------------- -**Cloud Commander** not using additional modules for main functionality. -But for minification and optimization tricks optional can be -assingned (and installed) modules: -- [UglifyJS] (https://github.com/mishoo/UglifyJS) -- [clean-css] (https://github.com/GoalSmashers/clean-css) -- [html-minifier] (https://github.com/kangax/html-minifier) -- [css-b64-images] (https://github.com/Filirom1/css-base64-images) \ No newline at end of file diff --git a/cloudcmd1/1/client.js b/cloudcmd1/1/client.js deleted file mode 100644 index 6331b051..00000000 --- a/cloudcmd1/1/client.js +++ /dev/null @@ -1,736 +0,0 @@ -/* Функция которая возвратит обьект CloudCommander - * @window - обьект window - * @document - обьект document - * @CloudFunc - обьект содержащий общий функционал - * клиентский и серверный - */ -//var CloudCommander=(function(window,document){ - -//var document,window; - -var CloudCommander=(function(){ -"use strict"; - -/* если функции console.log нет - создаём заглушку */ - -/* -var console; -if(!window)window={console:{log:function(pParam){return pParam;}}}; -else if(window && !window.console){ - console={ - 'log':function(param){ - return param; - } - }; -}else console=window.console; -*/ -/* - window.jQuery || document.write(' - - \ No newline at end of file diff --git a/cloudcmd1/1/package.json b/cloudcmd1/1/package.json deleted file mode 100644 index 5c67dd25..00000000 --- a/cloudcmd1/1/package.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "name": "cloudcmd", - "version": "0.0.1-9", - "scripts": { - "start": "server.js" - }, - "engines": { - "node": "0.6.x" - }, - "subdomain": "cloudcmd" -} \ No newline at end of file diff --git a/cloudcmd1/1/package2.json b/cloudcmd1/1/package2.json deleted file mode 100644 index f2d59387..00000000 --- a/cloudcmd1/1/package2.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "name": "cloudcmd", - "version": "0.0.1-3", - "scripts": { - - "start": "server.js" - }, - "engines": { - "node": "0.6.x" - }, - "subdomain": "cloudcmd" -} diff --git a/cloudcmd1/1/reset.css b/cloudcmd1/1/reset.css deleted file mode 100644 index a24c865b..00000000 --- a/cloudcmd1/1/reset.css +++ /dev/null @@ -1,100 +0,0 @@ -/* ============================================================================= - HTML5 display definitions - ========================================================================== */ - -/* -article, aside, details, figcaption, figure, footer, header, hgroup, nav, section { display: block; } -audio, canvas, video { display: inline-block; *display: inline; *zoom: 1; } -audio:not([controls]) { display: none; } -[hidden] { display: none; } -*/ - -/* ============================================================================= - Base - ========================================================================== */ - -/* - * 1. Correct text resizing oddly in IE6/7 when body font-size is set using em units - * 2. Prevent iOS text size adjust on device orientation change, without disabling user zoom: h5bp.com/g - */ - -html { font-size: 100%; -webkit-text-size-adjust: 100%; -ms-text-size-adjust: 100%; font-family: sans-serif; color: #222;} -body { margin: 0; font-size: 1em; line-height: 1.4; } - -/* - * Remove text-shadow in selection highlight: h5bp.com/i - * These selection declarations have to be separate - * Also: hot pink! (or customize the background color to match your design) - */ -/* -::-moz-selection { background: #fe57a1; color: #fff; text-shadow: none; } - ::selection { background: #fe57a1; color: #fff; text-shadow: none; } -*/ -::selection { text-shadow: none; opacity: 0;} - - -/* ============================================================================= - Links - ========================================================================== */ - -a {text-decoration:none; color: #00e; } -a:visited { color: #551a8b; } -a:hover { color: #06e; } -a:focus { outline: thin dotted; } - -/* Improve readability when focused and hovered in all browsers: h5bp.com/h */ -a:hover, a:active { outline: 0; } - -ul{ margin: 1em 0; padding: 0 0 0 40px; } - -/* - * 1. Display hand cursor for clickable form elements - * 2. Allow styling of clickable form elements in iOS - * 3. Correct inner spacing displayed oddly in IE7 (doesn't effect IE6) - */ - - -/* ============================================================================= - Chrome Frame Prompt - ========================================================================== */ - -.chromeframe { margin: 0.2em 0; background: #ccc; color: black; padding: 0.2em 0; } - - -/* ==|== non-semantic helper classes ======================================== - Please define your styles before this section. - ========================================================================== */ - -/* For image replacement */ -.ir { display: block; border: 0; text-indent: -999em; overflow: hidden; background-color: transparent; background-repeat: no-repeat; text-align: left; direction: ltr; *line-height: 0; } -.ir br { display: none; } - -/* Hide from both screenreaders and browsers: h5bp.com/u */ -.hidden { display: none !important; visibility: hidden; } - -/* Hide only visually, but have it available for screenreaders: h5bp.com/v */ -.visuallyhidden { border: 0; clip: rect(0 0 0 0); height: 1px; margin: -1px; overflow: hidden; padding: 0; position: absolute; width: 1px; } - -/* Extends the .visuallyhidden class to allow the element to be focusable when navigated to via the keyboard: h5bp.com/p */ -.visuallyhidden.focusable:active, .visuallyhidden.focusable:focus { clip: auto; height: auto; margin: 0; overflow: visible; position: static; width: auto; } - -/* Hide visually and from screenreaders, but maintain layout */ -.invisible { visibility: hidden; } - -/* Contain floats: h5bp.com/q */ -.clearfix:before, .clearfix:after { content: ""; display: table; } -.clearfix:after { clear: both; } -.clearfix { *zoom: 1; } - -/* ==|== print styles ======================================================= - Print styles. - Inlined to avoid required HTTP connection: h5bp.com/r - ========================================================================== */ - -@media print { - * { background: transparent !important; color: black !important; box-shadow:none !important; text-shadow: none !important; filter:none !important; -ms-filter: none !important; } /* Black prints faster: h5bp.com/s */ - a, a:visited { text-decoration: underline; } - a[href]:after { content: " (" attr(href) ")"; } - .ir a:after, a[href^="javascript:"]:after, a[href^="#"]:after { content: ""; } /* Don't show links for images, or javascript/internal links */ - @page { margin: 0.5cm; } -} \ No newline at end of file diff --git a/cloudcmd1/1/server.js b/cloudcmd1/1/server.js deleted file mode 100644 index 2839b1ef..00000000 --- a/cloudcmd1/1/server.js +++ /dev/null @@ -1,635 +0,0 @@ -"use strict"; - -/* Обьект содержащий все функции и переменные - * серверной части Cloud Commander'а - */ -var CloudServer={ - /* функция, которая генерирует заголовки - * файлов, отправляемые сервером клиенту - */ - generateHeaders :function(){}, - /* функция высылает - * данные клиенту - */ - sendResponse :function(){}, - /* Структура содержащая функции, - * и переменные, в которых - * говориться о поддерживаемых - * браузером технологиях - */ - BrowserSuport :{}, - /* Обьект для работы с кэшем */ - Cashe :{}, - /* Обьект через который - * выполняеться сжатие - * скриптов и стилей - */ - Minify :{}, - /* Асоциативный масив обьектов для - * работы с ответами сервера - * высылаемыми на запрос о файле и - * хранащий информацию в виде - * Responces[name]=responce; - */ - Responses :{}, - - /* ПЕРЕМЕННЫЕ */ - /* Поддержка браузером JS*/ - NoJS :true, - /* Поддержка gzip-сжатия - * браузером - */ - Gzip :undefined, - - /* КОНСТАНТЫ */ - /* index.html */ - INDEX :'index.html', - /* name of direcotory with libs */ - LIBDIR :'./lib', - LIBDIRSERVER :'./lib/server' -}; - -/* - * Обьект для работы с кэшем - * аналог клиентского обьекта - * с тем отличием, что в нём - * будут храниться серверные - * данные, такие как файлы - * отдаваемые клиенту - * (файлы проэкта по большому - * счёту, для ускорения - * первичной загрузки) - */ -CloudServer.Cache={ - _allowed :true, /* приватный переключатель возможности работы с кэшем */ - /* данные в которых храняться файлы - * в формате <поле> : <значение> - * _data[name]=pData; - * одному имени соответствуют - * одни данные - */ - _data :{}, - - /* функция говорит можно ли работать с кэшем */ - isAllowed :(function(){ - return CloudServer.Cache._allowed; - }), - /* функция устанавливает возможность работать с кэшем */ - setAllowed :(function(pAllowed){ - CloudServer.Cache._allowed=pAllowed; - }), - /* Если доступен кэш - * сохраняем в него данные - */ - set :(function(pName, pData){ - if(CloudServer.Cache._allowed && pName && pData){ - CloudServer.Cache._data[pName]=pData; - } - }), - /* Если доступен Cache принимаем из него данные*/ - get :(function(pName){ - if(CloudServer.Cache._allowed && pName){ - return CloudServer.Cache._data[pName]; - } - else return null; - }), - - /* Функция очищает кэш*/ - clear :(function(){ - if(CloudServer.Cache._allowed){ - CloudServer.Cache._data={}; - } - }) -}; - -/* Обьект для сжатия скриптов и стилей - * по умолчанию - сжимаються - */ -CloudServer.Minify={ - /* приватный переключатель минимизации */ - _allowed :{css:true,js:true,html:true, img: true}, - - /* функция разрешает или - * запрещает минимизировать - * css/js/html - * @pAllowed: - структура, в которой - * передаються параметры - * минификации, вида - * {js:true,css:true,html:false; img:true} - * img отвечает за перевод картинок в base64 - * и сохранение их в css-файл - */ - setAllowed :(function(pAllowed){ - if(pAllowed){ - this._allowed.css=pAllowed.css; - this._allowed.js=pAllowed.js; - this._allowed.html=pAllowed.html; - this._allowed.img=pAllowed.img; - } - }), - - /* - * Функция минимизирует css/js/html - * если установлены параметры минимизации - */ - doit :(function(){ - if(this._allowed.css || - this._allowed.js || - this._allowed.html){ - var lMinify = require(CloudServer.LIBDIRSERVER+'/minify'); - - this.done.js=this._allowed.js?lMinify.jsScripts():false; - this.done.html=this._allowed.html?lMinify.html():false; - this.done.css=this._allowed.css?lMinify.cssStyles(this._allowed.img):false; - } - }), - /* свойство показывающее случилась ли ошибка*/ - done:{js: false,css: false, html:false} -}; - - -var LeftDir='/'; -var RightDir=LeftDir; -/* - var Path = require('path'); -*/ /* модуль для работы с путями*/ - -var Fs = require('fs'); /* модуль для работы с файловой системой*/ - -var Zlib; -/* node v0.4 not contains zlib - */ -try{ - Zlib = require('zlib'); /* модуль для сжатия данных gzip-ом*/ -}catch(error){ - Zlib=undefined; - console.log('to use gzip-commpression' + - 'you should install zlib module\n' + - 'npm install zlib'); -} -var CloudFunc = require(CloudServer.LIBDIR + - (CloudServer.Minify.done.js?/* если стоит минификация*/ - '/cloudfunc.min':/* добавляем сжатый - иначе обычный */ - '/cloudfunc')); /* модуль с функциями */ -/* конструктор*/ -CloudServer.init=(function(){ - /* Переменная в которой храниться кэш*/ - CloudServer.Cache.setAllowed(true); - /* Change default parameters of - * js/css/html minification - */ - CloudServer.Minify.setAllowed({ - js:true, - css:true, - html:true, - img:true - }); - /* Если нужно минимизируем скрипты */ - CloudServer.Minify.doit(); -}); - - -/* создаём сервер на порту 31337*/ -CloudServer.start=function() -{ - CloudServer.init(); - - var http = require('http'); - http.createServer(CloudServer._controller).listen(process.env.PORT || - process.env.VCAP_APP_PORT /* cloudfoundry */ || - 31337, - '0.0.0.0' || '127.0.0.1'); - console.log('Cloud Commander server running at http://127.0.0.1:'+ - (process.env.PORT===undefined?31337:process.env.PORT)); -}; - - -/* Функция создаёт заголовки файлов - * в зависимости от расширения файла - * перед отправкой их клиенту - * @pName - имя файла - * @pGzip - данные сжаты gzip'ом - */ -CloudServer.generateHeaders = function(pName, pGzip){ - var lType=''; - /* высылаем заголовок в зависимости от типа файла */ - /* если расширение у файла css - - * загружаем стили - */ - if(CloudFunc.checkExtension(pName,'css')) - lType='text/css'; - /* загружаем js */ - else if(CloudFunc.checkExtension(pName,'js')) - lType='text/javascript'; - /* загружаем картинки*/ - else if(CloudFunc.checkExtension(pName,'png')) - lType='image/png'; - /* загружаем json*/ - else if(CloudFunc.checkExtension(pName,'json')) - lType='application/json'; - else if(CloudFunc.checkExtension(pName,'html')) - lType='text/html'; - else if(CloudFunc.checkExtension(pName,'appcache')) - lType='text/cache-manifest'; - /* если это неизвестный тип файла - - * высылаем его просто как текст - */ - else lType='text/plain'; - - return { - /* if type of file any, but img - - * then we shoud specify charset - */ - 'Content-Type': lType + (lType.indexOf('img')<0?'; charset=UTF-8':''), - 'cache-control': 'max-age='+(31337*21), - 'last-modified': new Date().toString(), - 'content-encoding': pGzip?'gzip':'', - /* https://developers.google.com/speed/docs/best-practices/caching?hl=ru#LeverageProxyCaching */ - 'Vary': 'Accept-Encoding' - }; -}; - -/* - * Главная функция, через которую проихсодит - * взаимодействие, обмен данными с клиентом - * @req - запрос клиента (Request) - * @res - ответ сервера (Response) - */ -CloudServer._controller=function(pReq, pRes) -{ - /* Читаем содержимое папки, - переданное в url - */ - var url = require("url"); - var pathname = url.parse(pReq.url).pathname; - console.log('pathname: '+pathname); - - /* получаем поддерживаемые браузером кодировки*/ - var lAcceptEncoding = pReq.headers['accept-encoding']; - /* запоминаем поддерживает ли браузер - * gzip-сжатие при каждом обращении к серверу - * и доступен ли нам модуль zlib - */ - if (lAcceptEncoding && - lAcceptEncoding.match(/\bgzip\b/) && - Zlib){ - CloudServer.Gzip=true; - }else - CloudServer.Gzip=false; - /* путь в ссылке, который говорит - * что js отключен - */ - var lNoJS_s=CloudFunc.NOJS; - var lFS_s=CloudFunc.FS; - - if(pathname!=='/favicon.ico') - { - console.log("request for " + pathname + " received..."); - var lName; - - /* если в пути нет информации ни о ФС, - * ни об отсутствии js, - * ни о том, что это корневой - * каталог - загружаем файлы проэкта - */ - if(pathname.indexOf(lFS_s)<0 && - pathname.indexOf(lNoJS_s)<0 && - pathname!=='/'){ - /* если имена файлов проекта - загружаем их*/ - /* убираем слеш и читаем файл с текущец директории*/ - //lName=Path.basename(pathname); - - /* добавляем текующий каталог к пути */ - lName='.'+pathname; - console.log('reading '+lName); - /* сохраняем указатель на responce и имя */ - CloudServer.Responses[lName]=pRes; - - /* Берём значение из кэша - * сжатый файл - если gzip-поддерживаеться браузером - * не сжатый - в обратном случае - */ - var lFileData=CloudServer.Cache.get(CloudServer.Gzip?(lName+'_gzip'):lName); - - var lReadFileFunc_f=CloudServer.getReadFileFunc(lName); - /* если там что-то есть передаём данные в функцию - * readFile - */ - if(lFileData){ - console.log('readed from cache'); - /* передаём данные с кэша, - * если gzip включен - сжатые - * в обратном случае - несжатые - */ - lReadFileFunc_f(undefined,lFileData,true); - } - else Fs.readFile(lName,lReadFileFunc_f); - - }else{/* если мы имеем дело с файловой системой*/ - /* если путь не начинаеться с no-js - значит - * js включен - */ - /* убираем пометку cloud, без которой c9.io - * не работает поскольку путь из двух слешей - * (/fs/no-js/) - очень короткий, нужно - * длиннее - */ - - if(pathname.indexOf(lNoJS_s)!==lFS_s.length && pathname!=='/'){ - CloudServer.NoJS=false; - }else pathname=pathname.replace(lNoJS_s,''); - - /* убираем индекс файловой системы */ - if(pathname.indexOf(lFS_s)===0){ - pathname=pathname.replace(lFS_s,''); - /* если посетитель только зашел на сайт - * no-js будет пустым, как и fs - */ - /* если в пути нету fs - посетитель только зашел на сайт - * загружаем его полностью. - */ - }else CloudServer.NoJS=true; - /* если в итоге путь пустой - * делаем его корневым - */ - if(pathname==='')pathname='/'; - - RightDir=pathname; - LeftDir=pathname; - - /* если встретиться пробел - - * меня код символа пробела на пробел - */ - - LeftDir=CloudFunc.replaceSpaces(LeftDir); - RightDir=CloudFunc.replaceSpaces(RightDir); - - /* Проверяем с папкой ли мы имеем дело */ - - /* читаем сновные данные о файле */ - var lStat; - try{ - lStat=Fs.statSync(LeftDir); - }catch(error){ - console.log(error); - CloudServer.Responses[LeftDir]=pRes; - CloudServer.sendResponse('OK',error.toString(),LeftDir); - } - /* если это каталог - - * читаем его содержимое - */ - try{ - /* если установлено сжатие - * меняем название html-файла и - * загружаем сжатый html-файл в дальнейшем - */ - CloudServer.INDEX=(CloudServer.Minify.done.html?'index.min.html':CloudServer.INDEX); - /* - * сохраним указатель на response - */ - CloudServer.Responses[CloudServer.INDEX]=pRes; - if(lStat.isDirectory()) - Fs.readdir(LeftDir,CloudServer._readDir); - /* отдаём файл */ - else if(lStat.isFile()){ - CloudServer.Responses[LeftDir]=pRes; - Fs.readFile(LeftDir,CloudServer.getReadFileFunc(LeftDir)); - console.log('reading file: '+LeftDir); - } - }catch(error){console.log(error);} - } - } -}; - -/* Функция читает ссылку или выводит информацию об ошибке*/ -CloudServer._readDir=function (pError, pFiles) -{ - if(!pError) - { - /* данные о файлах в формате JSON*/ - var lJSON=[]; - var lJSONFile={}; - /* Если мы не в корне добавляем слеш к будующим ссылкам */ - if(LeftDir!=='/') - { - RightDir+='/'; - LeftDir+='/'; - } - - pFiles=pFiles.sort(); - - lJSON[0]={path:LeftDir,size:'dir'}; - var fReturnFalse=function returnFalse(){return false;}; - for(var i=0;i','') - .replace('style.css','all.min.css') - :lIndex; - - lIndex = CloudServer.Minify.done.js?lIndex.replace('client.js','client.min.js'):lIndex; - - lIndex=lIndex.toString().replace('
    ','
    '+lList); - /* меняем title */ - lIndex=lIndex.replace('Cloud Commander', - ''+CloudFunc.setTitle()+''); - /* отображаем панель быстрых клавишь */ - lList=lIndex; - /* если браузер поддерживает gzip-сжатие*/ - lHeader=CloudServer.generateHeaders('text/html',CloudServer.Gzip); - }catch(error){console.log(error);} - }else{ - /* в обычном режиме(когда js включен - * высылаем json-структуру файлов - * с соответствующими заголовками - */ - lList=JSON.stringify(lJSON); - lHeader=CloudServer.generateHeaders('application/json',CloudServer.Gzip); - } - /* если браузер поддерживает gzip-сжатие - сжимаем данные*/ - if(CloudServer.Gzip){ - Zlib.gzip(lList,CloudServer.getGzipDataFunc(lHeader,CloudServer.INDEX)); - } - /* если не поддерживаеться - отсылаем данные без сжатия*/ - else - CloudServer.sendResponse(lHeader,lList,CloudServer.INDEX); - } - else - { - console.log(pError); - CloudServer.sendResponse('OK',pError.toString()); - } -}; - -/* Функция генерирует функция считывания файла - * таким образом, что бы у нас было - * имя считываемого файла - * @pName - полное имя файла - */ -CloudServer.getReadFileFunc = function(pName){ -/* - * @pError - ошибка - * @pData - данные - * @pFromFile - прочитано с файла bool - */ - var lReadFile=function(pError,pData,pFromCache_b){ - if (!pError){ - console.log('file ' + pName + ' readed'); - - /* берём из кэша данные файла - * если их нет в кэше - - * сохраняем - */ - if(!pFromCache_b && CloudServer.Cache.isAllowed) - CloudServer.Cache.set(pName,pData); - /* если кэш есть - * сохраняем его в переменную - * которая до этого будет пустая - * по скольку мы будем вызывать этот метод - * сами, ведь файл уже вычитан - */ - - var lHeader=CloudServer.generateHeaders(pName,CloudServer.Gzip); - /* если браузер поддерживает gzip-сжатие - сжимаем данные*/ - if(CloudServer.Gzip &&!pFromCache_b){ - /* сжимаем содержимое */ - Zlib.gzip(pData,CloudServer.getGzipDataFunc(lHeader,pName)); - } - else{ - /* высылаем несжатые данные */ - CloudServer.sendResponse(lHeader,pData,pName); - } - } - else - { - console.log(pError.path); - if(pError.path!=='passwd.json') - { - console.log(pError); - CloudServer.sendResponse('OK',pError.toString()); - }else{ - CloudServer.sendResponse('OK','passwd.json'); - } - } - }; - return lReadFile; -}; - -/* Функция получает сжатые данные - * @pHeader - заголовок файла - */ -CloudServer.getGzipDataFunc=function(pHeader,pName){ - return function(error,pResult){ - if(!error){ - /* отправляем сжатые данные - * вместе с заголовком - */ - /* если установлена работа с кэшем - * сохраняем сжатые данные - */ - if(CloudServer.Cache.isAllowed){ - /* устанавливаем кєш */ - console.log(pName+' gziped'); - CloudServer.Cache.set(pName+'_gzip',pResult); - } - CloudServer.sendResponse(pHeader,pResult,pName); - } - else{ - console.log(error); - CloudServer.sendResponse(pHeader,error); - } - }; -}; -/* Функция высылает ответ серверу - * @pHead - заголовок - * @pData - данные - * @pName - имя отсылаемого файла - */ -CloudServer.sendResponse = function(pHead, pData,pName){ - /* если у нас есть указатель на responce - * для соответствующего файла - - * высылаем его - */ - var lResponse=CloudServer.Responses[pName]; - if(lResponse){ - lResponse.writeHead(200,pHead); - lResponse.end(pData); - console.log(pName+' sended'); - } -}; - -CloudServer.start(); \ No newline at end of file diff --git a/cloudcmd1/1/style.css b/cloudcmd1/1/style.css deleted file mode 100644 index 57136168..00000000 --- a/cloudcmd1/1/style.css +++ /dev/null @@ -1,317 +0,0 @@ -/* -@import url(//fonts.googleapis.com/css?family=Droid+Sans+Mono); -*/ - -/* Foundation Icons General Enclosed */ -@font-face { - font-family: 'FoundationIconsGeneralEnclosed'; - src: url('//dl.dropbox.com/u/78163899/mnemonia/fonts/foundation-icons-general-enclosed.woff') format('woff'); - font-weight: normal; - font-style: normal; - -} -/* символьный шрифт от гитхаба*/ -@font-face { - font-family: 'Octicons Regular'; - font-style: normal; - font-weight: normal; - src: local('Octicons Regular'), url('//dl.dropbox.com/u/78163899/mnemonia/fonts/octicons-regular-webfont.woff') format('woff'); -} - -@font-face { - font-family: 'Droid Sans Mono'; - font-style: normal; - font-weight: normal; - src: local('Droid Sans Mono'), local('DroidSansMono'), url('http://themes.googleusercontent.com/static/fonts/droidsansmono/v4/ns-m2xQYezAtqh7ai59hJUYuTAAIFFn5GTWtryCmBQ4.woff') format('woff'); -} - -body{ - font:16px "Droid Sans Mono"; -} - -.menu{ - font: 16px 'Octicons Regular'; - margin-bottom: 0; -} - -.path_icon{ - font-family:'FoundationIconsGeneralEnclosed'; - font-size:30px; - color: #46A4C3;/*#55BF3F; green*/ - text-shadow:black 0 2px 1px; - /* размер иконки и позиция на png-файле*/ - width: 15px; - height: 15px; - display: inline-block; - position: relative; - top: 3px; - left: -4px; -} -.path_icon:hover{ - /* - color:#45D827; - */ - cursor:pointer; -} -.path_icon:active{ - text-shadow:black 0 0 1px; - position: relative; - top: 4px; -} -.icon{ - font-family: 'Octicons Regular'; - font-size:16px; - width:16px; - height:16px; - display:inline-block; - margin-left:0.5%; -} -.error::before{ - content:'\f026'; - cursor:default; - color:rgb(222, 41, 41); - position: relative; - top: -3px; -} -.loading{ - background:url(/img/spinner.gif); - position:relative; - top:1px; -} -.error:hover{ - color:rgba(222, 41, 41, 0.81); -} -.refresh-icon{ - background:url(/img/panel_refresh.png) no-repeat; -} -.refresh-icon:active{ - /*background-position-y: -15px;*/ -background:url(/img/panel_refresh.png) 0 -15px no-repeat; -} -.clear-cache{ - background:url(/img/console_clear.png) -4px -4px no-repeat; - margin-right: 6px; - margin-left: 7px; -} -.clear-cache:active{ - /* - background-position-y: -25px; - */ - top:5px; -} - -.settings:before{ - content:'k'; -} -.links{ - color:red; - } - -.mini-icon { - float: left; - height: 16px; - left: -5px; - margin-left: 6px; - position: relative; - top: 2px; - width: 16px; - /* отступ перед картинкой - * для нормального отображения - * рамки - */ -} -/* freeupex */ -.directory{ - /*list-style-image*/ - background-image:url('/img/dir.png'); - background-repeat: no-repeat; - background-position: 0 0; -} -.text-file{ - /*list-style-image*/ - background-image:url('/img/txt.png'); - background-repeat: no-repeat; - background-position: 0 0; -} -#fm{ - height:90%; - overflow-y: scroll; -} -.fm_header{ - font-weight: bold; -} -#path{ - margin-left:1.5%; -} -#left{ - float:left; - width:90%; -} -/* фон файла, на котором курсор*/ -.current-file{ - border: 2px solid rgba(49, 123, 249, .40); -} -.selected-file{ - background-color: rgba(49, 123, 249, .40); - color:white; -} -#right{ - float:right; -} -.panel{ - display: table; - width:45%; -} -#keyspanel{ - text-align: center; -} -/* информация о файлах и папках*/ -.name{ - float: left; - width: 37%; -} -.size{ - float:left; - width:16%; - /* Ставим выравнивание, - * что бы размер был в - * одной ровной колонке - */ - text-align: right; - /* Ставим отступ, что бы - * size не налазил на uid - * (owner) - */ - margin-right: 27px; -} -.owner{ -} -.mode{ - float: right; - width: 25%; -} - -ul,li{list-style-type:none;} -button{ - width:10%; -} -a{ - text-decoration:none; -} -a:hover, a:active { cursor:pointer;outline: 0; color: #06e; } -a:focus { outline: thin dotted; } - -/* Если размер окна очень маленький - * располагаем имя и атрибуты файла - * друг-под-другом -*/ -/* responsive design */ -@media only screen and (max-width: 600px){ - #left{ - width:90% !important; - } - .panel >li{ - margin:10px; - } - /* если правая панель не помещаеться - прячем её */ - #right{ - display:none; - } - /* текущий файл под курсором */ -.current-file{ - background-color: rgba(49, 123, 249, .40); - color:white; - } - /* делаем иконки под курсом белыми*/ -.current-file > .mini-icon{ - color:white; - } -.current-file > .text-file::before{ - color:white; - } - -/* меняем иконки на шрифтовые*/ - .mini-icon { - font: 60px 'Octicons Regular'; - width: 40%; - height: 0; - margin-left: 0; - float: right; - position: relative; - top: -17px; - - color: rgba(246, 224, 124, 0.56); - } - .directory::before{ - content: '\f216'; - } - .text-file::before{ - color: rgba(26, 224, 124, 0.56); - content: '\f211'; - } - .text-file{ - background-image:none; - } - - - - /* убираем заголовок*/ - .fm_header{ - display:none; - } - .mode,.size,.owner{ - /* располагаем элементы - * один под другим - */ - display: table; - float: none; - width: 0; - - text-align: left; - } - /* выводим заголовки рядом с полями */ - .name::before{ - content: 'name:'; - font-weight: bold; - font-size: 13px; - } - .mode::before{ - content: 'mode:'; - font-weight: bold; - font-size: 13px; - } - .size::before{ - content: 'size:'; - font-weight: bold; - font-size: 13px; - } - .owner::before{ - content: 'owner:'; - font-weight: bold; - font-size: 13px; - } - - .name{ - float: none; - width:100%; - font-size: 18px; - } -} -@media only screen and (min-width: 601px) and (max-width: 767px){ - #left{ - width:90% !important; - } - #right{ - display:none; - } -} - -@media only screen and (min-width:767px) and (max-width: 1060px){ - #left{ - width:90% !important; - } - /* если правая панель не помещаеться - прячем её */ - #right{ - display:none; - } -} \ No newline at end of file diff --git a/cloudcmd1/1/test.sh b/cloudcmd1/1/test.sh deleted file mode 100644 index 6b68a51f..00000000 --- a/cloudcmd1/1/test.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh -npm i -g jshint -echo "jshint server.js client.js lib/cloudfunc.js" -jshint --config ./.jshintrc ./server.js ./client.js ./lib/cloudfunc.js \ No newline at end of file diff --git a/cloudcmd1/README.md b/cloudcmd1/README.md deleted file mode 100644 index 49cf0cba..00000000 --- a/cloudcmd1/README.md +++ /dev/null @@ -1,49 +0,0 @@ -Cloud Commander [![Build Status](https://secure.travis-ci.org/coderaiser/cloudcmd.png?branch=master)](http://travis-ci.org/coderaiser/cloudcmd) -=============== -**Cloud Commander** - two-panels file manager, totally writed on js. -View [demo](http://demo-cloudcmd.cloudfoundry.com/ "demo"). - -Google PageSpeed Score : [100](https://developers.google.com/speed/pagespeed/insights#url=http_3A_2F_2Fdemo-cloudcmd.cloudfoundry.com_2F&mobile=false "score") (out of 100). - -Benefits ---------------- -- full browser compatibility *(ie6+,chrome,safari,opera,firefox)*; -- responsible design -- one full page loading, *and then just one-time json-dir-listings loading -(with refresh opportunity).* -- caching readed directories *to localStorage (for now) -(so if network will disconnected or something heppen with a signal, we -definitely will can work cached copy of directory listings)*; -- key binding -- disabled js support *(working in limited mode)*. -- automated minification *client js-files and onstart-reading Cloud manager files on server starting.* - -**Cloud Commander** uses all benefits of js, so if js is disabled, -we moves to *limited mode*. - -Limited-mode features: ---------------- -- only 1 panel available -- no keybinding -- no local caching -- full loading of all web page(with styles, js-scripts, html-page etc). - -Hot keys: ---------------- -In all modern web browsers (but not in IE, becouse he special) hot keys works. -There is a short list: -- Ctrl + r - reload dir content -- Alt + q - disable key bindings -- Alt + s - get all key bindings back -- up, down, enter - filesystem navigation - - -Additional modules: ---------------- -**Cloud Commander** not using additional modules for main functionality. -But for minification and optimization tricks optional can be -assingned (and installed) modules: -- [UglifyJS] (https://github.com/mishoo/UglifyJS) -- [clean-css] (https://github.com/GoalSmashers/clean-css) -- [html-minifier] (https://github.com/kangax/html-minifier) -- [css-b64-images] (https://github.com/Filirom1/css-base64-images) \ No newline at end of file diff --git a/cloudcmd1/client.js b/cloudcmd1/client.js deleted file mode 100644 index 6331b051..00000000 --- a/cloudcmd1/client.js +++ /dev/null @@ -1,736 +0,0 @@ -/* Функция которая возвратит обьект CloudCommander - * @window - обьект window - * @document - обьект document - * @CloudFunc - обьект содержащий общий функционал - * клиентский и серверный - */ -//var CloudCommander=(function(window,document){ - -//var document,window; - -var CloudCommander=(function(){ -"use strict"; - -/* если функции console.log нет - создаём заглушку */ - -/* -var console; -if(!window)window={console:{log:function(pParam){return pParam;}}}; -else if(window && !window.console){ - console={ - 'log':function(param){ - return param; - } - }; -}else console=window.console; -*/ -/* - window.jQuery || document.write(' - - \ No newline at end of file diff --git a/cloudcmd1/lib/README.md b/cloudcmd1/lib/README.md deleted file mode 100644 index a741f80c..00000000 --- a/cloudcmd1/lib/README.md +++ /dev/null @@ -1,5 +0,0 @@ -Cloud Commander Libraries -=============== -**Cloud Commander Libraries** - dir thet contains scripts, thet uses -on client and server side, and modules, wich is not necessary -for CloudCommander work, but they adds some sugor. \ No newline at end of file diff --git a/cloudcmd1/lib/client/keyBinding.js b/cloudcmd1/lib/client/keyBinding.js deleted file mode 100644 index 2416002e..00000000 --- a/cloudcmd1/lib/client/keyBinding.js +++ /dev/null @@ -1,248 +0,0 @@ -var CloudCommander; -var CloudFunc; -CloudCommander.keyBinding=(function(){ - "use strict"; - var key_event=function(event){ - /* - * Делаем допущение что перезагружать Cloud Commander - * посетителям не придёться, в любом случае, параметр - * должен быть опциональным и должна быть возможность - * его отключить. В любом случае, кроме хакеров и - * разработчиков (при чём сомнительно, что хакерам - * это пригодиться), функция перезагрузки никому не - * нужна, поскольку загружать весь дополнительный - * контент снова (js,css) в готовой версии нет - * необходимости. - * - */ - //console.log(event.keyCode); - var lCurrentFile; - var lName; - /* если клавиши можно обрабатывать*/ - if(CloudCommander.keyBinded){ - /* если нажали таб: - * переносим курсор на - * правую панель, если - * мы были на левой и - * наоборот - */ - if(event.keyCode===9){ - console.log('Tab pressed'); - try{ - lCurrentFile=document.getElementsByClassName(CloudCommander.CURRENT_FILE)[0]; - }catch(error){console.log(error);} - } - /* навигация по таблице файлов*/ - /* если нажали клавишу вверх*/ - else if(event.keyCode===38){ - /* получаем выдленный файл*/ - lCurrentFile=document.getElementsByClassName(CloudCommander.CURRENT_FILE); - /* если ненайдены выделенные файлы - выходим*/ - if(lCurrentFile.length===0)return; - lCurrentFile=lCurrentFile[0]; - /* если это строка существет и - * если она не заголовок - * файловой таблицы - */ - if(lCurrentFile.previousSibling && - lCurrentFile.previousSibling.className!=='fm_header' ){ - /* убираем выделение с текущего элемента */ - lCurrentFile.className=''; - /* и выделяем предыдущую строку*/ - lCurrentFile.previousSibling.className=CloudCommander.CURRENT_FILE; - event.preventDefault(); - } - } - /* если нажали клавишу в низ*/ - else if(event.keyCode===40){ - /* получаем выдленный файл*/ - lCurrentFile=document.getElementsByClassName(CloudCommander.CURRENT_FILE); - /* если ненайдены выделенные файлы - выходим*/ - if(lCurrentFile.length===0)return; - lCurrentFile=lCurrentFile[0]; - /* если это не последняя строка */ - if(lCurrentFile.nextSibling){ - /* убираем с него выделение */ - lCurrentFile.className=''; - /* выделяем следующую строку*/ - lCurrentFile.nextSibling.className=CloudCommander.CURRENT_FILE; - event.preventDefault(); - } - } - /* если нажали клавишу page up или Home - * переходим к самому верхнему - * элементу - */ - else if(/*event.keyCode===33 ||*/ event.keyCode===36){ - lCurrentFile=document.getElementsByClassName(CloudCommander.CURRENT_FILE)[0]; - /* убираем выделение с текущего файла*/ - lCurrentFile.className=''; - /* получаем первый элемент*/ - lCurrentFile.parentElement.firstElementChild - /* пропускаем путь и заголовки столбиков*/ - .nextElementSibling.nextElementSibling - /* выделяем верхий файл */ - .className=CloudCommander.CURRENT_FILE; - } - /* если нажали клавишу page down или End - * выделяем последний элемент - */ - else if(/*event.keyCode===34 ||*/ event.keyCode===35){ - lCurrentFile=document.getElementsByClassName(CloudCommander.CURRENT_FILE)[0]; - /* снимаем выделение с текущего файла*/ - lCurrentFile.className=''; - /* выделяем самый нижний файл */ - lCurrentFile.parentElement.lastElementChild.className=CloudCommander.CURRENT_FILE; - } - /* если нажали Enter - открываем папку*/ - else if(event.keyCode===13){ - lCurrentFile=document.getElementsByClassName(CloudCommander.CURRENT_FILE); - /* если ненайдены выделенные файлы - выходим*/ - if(!lCurrentFile.length)return; - lCurrentFile=lCurrentFile[0]; - /* из него достаём спан с именем файла*/ - lName=lCurrentFile.getElementsByClassName('name'); - /* если нету (что вряд ли) - выходим*/ - if(!lName)return false; - /* достаём все ссылки*/ - var lATag=lName[0].getElementsByTagName('a'); - /* если нету - выходим */ - if(!lATag)return false; - /* получаем ссылку на каталог, - * что на уровень выше - */ - /* получаем имя каталога в котором находимся*/ - var lHref; - try{ - lHref=lCurrentFile.parentElement.getElementsByClassName('path')[0].innerText; - }catch(error){console.log('error');} - lHref=CloudFunc.removeLastSlash(lHref); - var lSubstr=lHref.substr(lHref,lHref.lastIndexOf('/')); - lHref=lHref.replace(lSubstr+'/',''); - - /* вызываем ajaxload привязанный через changelinks - * пробулем нажать на ссылку, если не получиться - * (opera, ie), вызываем событие onclick, - * которое пока не прописано у файлов - */ - - if(lCurrentFile.onclick)lCurrentFile.onclick(true); - else try{ - lATag[0].click(); - } - catch(error){ - console.log(error); - } - } - /* если нажали +r */ - else if(event.keyCode===82 && - event.ctrlKey){ - console.log('+r pressed'); - console.log('reloading page...'); - console.log('press +q to remove all key-handlers'); - - /* обновляем страницу, */ - /* Загружаем содержимое каталога - * при этом данные берём всегда из - * сервера, а не из кэша - * (обновляем кэш) - */ - /* Программно нажимаем на кнопку перезагрузки - * содержимого каталога - */ - var lRefreshIcon=document.getElementsByClassName(CloudFunc.REFRESHICON); - if(lRefreshIcon)lRefreshIcon=lRefreshIcon[0]; - if(lRefreshIcon){ - /* находим файл который сейчас выделен */ - lCurrentFile=document.getElementsByClassName(CloudCommander.CURRENT_FILE); - if(lCurrentFile.length>0)lCurrentFile=lCurrentFile[0]; - /* получаем название файла*/ - var lSelectedName=lCurrentFile.getElementsByTagName('a')[0].innerText; - /* если нашли элемент нажимаем него - * а если не можем - нажимаем на - * ссылку, на которую повешен eventHandler - * onclick - */ - if(lRefreshIcon.click)lRefreshIcon.parentElement.click(); - else lRefreshIcon.parentElement.onclick(); - - /* перебираем файлы левой панели - * в поисках подсвеченого файла - */ - var lLeft=document.getElementById('left'); - if(lLeft){ - /* перебираем все файлы в панели */ - var lLi=lLeft.getElementsByTagName('li'); - lCurrentFile.className=''; - /* начинаем с 2-ух, по скольку - * 0 - это путь - * 1 - это заголовок файловой таблицы - */ - for(var i=2;i+d чистим кэш */ - else if(event.keyCode===68 && - event.ctrlKey){ - console.log('+d pressed'); - console.log('clearing cache...'); - console.log('press +q to remove all key-handlers'); - - var lClearCache=document.getElementById('clear-cache'); - if(lClearCache && lClearCache.onclick)lClearCache.onclick(); - - event.preventDefault();//запрет на дальнейшее действие - } - /* если нажали +q - * убираем все обработчики - * нажатий клавиш - */ - else if(event.keyCode===81 && - event.altKey){ - //document.removeEventListener('keydown', key_event,false); - console.log('+q pressed'); - console.log('+r reload key-handerl - removed'); - console.log('+s clear cache key-handler - removed'); - console.log('press +s to to set them'); - - /* обработчик нажатий клавиш снят*/ - CloudCommander.keyBinded=false; - } - } - /* если нажали +s - * устанавливаем все обработчики - * нажатий клавиш - */ - else if(event.keyCode===83 && - event.altKey){ - /* - document.addEventListener('keydown', key_event,false); - */ - /* обрабатываем нажатия на клавиши*/ - CloudCommander.keyBinded=true; - - console.log('+s pressed'); - console.log('+r reload key-handerl - set'); - console.log('+s clear cache key-handler - set'); - console.log('press +q to remove them'); - } - - return false; - }; - /* добавляем обработчик клавишь */ - if(document.addEventListener) - document.addEventListener('keydown', key_event,false); - else document.onkeypress=key_event; - /* клавиши назначены*/ - CloudCommander.keyBinded=true; -}); \ No newline at end of file diff --git a/cloudcmd1/lib/cloudfunc.js b/cloudcmd1/lib/cloudfunc.js deleted file mode 100644 index 2c1c62b0..00000000 --- a/cloudcmd1/lib/cloudfunc.js +++ /dev/null @@ -1,513 +0,0 @@ -"use strict"; -/* Модуль, содержащий функции, которые будут работать - * и на клиенте и на сервере - * - * Правила названий: - * varName - имя функции - * lVarName - имя локальной переменной - * pVarName - имя параметра - * fVarName - имя функции созданной внутри функции - * VARNAME - имя константы - * - * Типы переменных: - * varNameS - строка - * varNameN - число - * varNameO - обьект - * varNameM - массив - */ - -var CloudFunc={ - /* Путь с которым мы сейчас работаем */ - Path :'', - /* КОНСТАНТЫ (общие для клиента и сервера)*/ - /* название программы */ - NAME :'Cloud Commander', - /* если в ссылке будет эта строка - - * в браузере js отключен - */ - NOJS : '/no-js', - FS : '/c/f/s', - /* название css-класа кнопки обновления файловой структуры*/ - REFRESHICON : 'refresh-icon', - /* id панелей с файлами */ - LEFTPANEL : 'left', - RIGHTPANEL : 'right' - /* name of direcotory with libs */ -}; - -/* - * Функция убирает последний слеш, - * если он - последний символ строки - */ -CloudFunc.removeLastSlash = function(pPath){ - if(typeof pPath==='string') - return (pPath.lastIndexOf('/')===pPath.length-1)? - pPath.substr(pPath, pPath.length-1):pPath; - else return pPath; -}; -/* - * Функция меняет код символа пробела на пробел - * в переданной строке - * @pPath - строка - */ -CloudFunc.replaceSpaces = function(pPath){ - if(pPath.indexOf('%20')>0){ - do{ - pPath=pPath.replace('%20',' '); - }while(pPath.indexOf('%20')>0); - } - return pPath; -}; - -/* Функция возвращает заголовок веб страницы */ -CloudFunc.setTitle = function(){ - - return CloudFunc.Path===''?CloudFunc.NAME: - CloudFunc.Path + - ' - ' + - CloudFunc.NAME; -}; -/* Функция переводит права из цыфрового вида в символьный - * @pPerm_s - строка с правами доступа - * к файлу в 8-миричной системе - */ -CloudFunc.convertPermissionsToSymbolic= function(pPerm_s){ - /* - S_IRUSR 0000400 protection: readable by owner - S_IWUSR 0000200 writable by owner - S_IXUSR 0000100 executable by owner - S_IRGRP 0000040 readable by group - S_IWGRP 0000020 writable by group - S_IXGRP 0000010 executable by group - S_IROTH 0000004 readable by all - S_IWOTH 0000002 writable by all - S_IXOTH 0000001 executable by all - */ - if(pPerm_s===undefined) return; - - /* тип файла */ - var lType=pPerm_s.charAt(0); - - switch (lType-0) { - case 1: /* обычный файл */ - lType='-'; - break; - case 2: /* байт-ориентированное (символьное) устройство*/ - lType='c'; - break; - case 4: /* каталог */ - lType='d'; - break; - default: - lType='-'; - } - - /* оставляем последние 3 символа*/ - pPerm_s=pPerm_s.length>5?pPerm_s.substr(3):pPerm_s.substr(2); - - /* Рекомендации гугла советуют вместо string[3] - * использовать string.charAt(3) - */ -/* - http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml?showone=Standards_features#Standards_features - - Always preferred over non-standards featuresFor - maximum portability and compatibility, always - prefer standards features over non-standards - features (e.g., string.charAt(3) over string[3] - and element access with DOM functions instead - of using an application-specific shorthand). -*/ - /* Переводим в двоичную систему */ - var lOwner=(pPerm_s[0]-0).toString(2); - var lGroup=(pPerm_s[1]-0).toString(2); - var lAll =(pPerm_s[2]-0).toString(2); - /* - console.log(lOwner+' '+lGroup+' '+lAll); - */ - /* переводим в символьную систему*/ - var lPermissions=//lType+' '+ - (lOwner[0]-0>0?'r':'-')+ - (lOwner[1]-0>0?'w':'-')+ - (lOwner[2]-0>0?'x':'-')+ - ' ' + - (lGroup[0]-0>0?'r':'-')+ - (lGroup[1]-0>0?'w':'-')+ - (lGroup[2]-0>0?'x':'-')+ - ' ' + - (lAll[0]-0>0?'r':'-')+ - (lAll[1]-0>0?'w':'-')+ - (lAll[2]-0>0?'x':'-'); - /* - console.log(lPermissions); - */ - return lPermissions; -}; - -/* Функция конвертирует права доступа к файлам из символьного вида - * в цыфровой - */ -CloudFunc.convertPermissionsToNumberic= function(pPerm_s){ - /* если передана правильная строка, конвертированная - * функциец convertPermissionsToSymbolic - */ - if(!pPerm_s || pPerm_s.length!==11)return pPerm_s; - - var lOwner= (pPerm_s[0]==='r'?4:0) + - (pPerm_s[1]==='w'?2:0) + - (pPerm_s[2]==='x'?1:0); - var lGroup= (pPerm_s[4]==='r'?4:0) + - (pPerm_s[5]==='w'?2:0) + - (pPerm_s[6]==='x'?1:0); - var lAll = (pPerm_s[8]==='r'?4:0) + - (pPerm_s[9]==='w'?2:0) + - (pPerm_s[10]==='x'?1:0); - /* добавляем 2 цыфры до 5 */ - return '00'+lOwner+lGroup+lAll; -}; -/* Функция получает короткие размеры - * конвертируя байт в килобайты, мегабойты, - * гигайбайты и терабайты - * @pSize - размер в байтах - */ -CloudFunc.getShortedSize=function(pSize){ - /* Константі размеров, что используются - * внутри функции - */ - var l1BMAX=1024; - var l1KBMAX=1048576; - var l1MBMAX=1073741824; - var l1GBMAX=1099511627776; - var l1TBMAX=1125899906842624; - - var lShorted; - - if(pSize2){ - if(folders[0].lastIndexOf('/')===folders[0].length) - LPrevDir=folders[1]; - else LPrevDir=folders[2]; - }else LPrevDir='/'; - */ - /* ################################### */ - - /* Формируем ссылки на каждый каталог в пути */ - var lHref=''; - var lHrefEnd=''; - - var lHtmlPath; - /* путь в ссылке, который говорит - * что js отключен - */ - var lNoJS_s=CloudFunc.NOJS; - var lFS_s=CloudFunc.FS; - /* корневой каталог */ - lHtmlPath=lHref+lFS_s+lNoJS_s+lTitle+'"/"'+_l+'/'+lHrefEnd; - for(i=folders.length-1;i>0;i--) - { - var lUrl=folders[i]; - var lShortName=lUrl.replace(lUrl.substr(lUrl,lUrl.lastIndexOf('/')+1),''); - if(i!==1) - { - lHtmlPath+=lHref+lFS_s+lNoJS_s+lUrl+lTitle+lUrl+_l+lShortName+lHrefEnd+'/'; - } - else - lHtmlPath+=lShortName+'/'; - } - /* *** */ - return lHtmlPath; -}; - -/* - * Функция ищет в имени файла расширение - * и если находит возвращает true - * @pName - получает имя файла - * @pExt - расширение - */ -CloudFunc.checkExtension=function(pName,pExt) -{ - /* если длина имени больше - * длинны расширения - - * имеет смысл продолжать - */ - if(pName.length>pExt.length){ - var lLength=pName.length; /* длина имени*/ - var lExtNum=pName.lastIndexOf(pExt);/* последнее вхождение расширения*/ - var lExtSub=lLength-lExtNum; /* длина расширения*/ - /* если pExt - расширение pName */ - if(lExtSub===pExt.length) - return true; - else - return false; - } - else return false; -}; - -/* - * Функция формирует заголовки столбиков - * @pFileTableTitles - массив названий столбиков - */ -CloudFunc._getFileTableHeader=function(pFileTableTitles) -{ - var lHeader='
  • '; - lHeader+=''; - for(var i=0;i'+ - lStr+ - ''; - } - lHeader+='
  • '; - - return lHeader; -}; - -/* - * Функция строит таблицу файлв из JSON-информации о файлах - * @pJSON - информация о файлах - * @pKeyBinded - если клавиши назначены, выделяем верхний файл - * [{path:'путь',size:'dir'}, - * {name:'имя',size:'размер',mode:'права доступа'}] - */ -CloudFunc.buildFromJSON=function(pJSON,pKeyBinded) -{ - var files; - /* - * если пропарсить стандартными - * функциями нельзя - - * пробуем eval, - */ - /* - * Если мы на клиенте и нет JSON - - * через eval парсим. - * Если-же мы на сервере, - * или на клиенте всё есть - * парсим стандарным методом - */ - - /* По скольку мы прописали заголовок application/json - * нет необходимости его конвертировать, - * но она есть, если мы вытягиваем данные из - * localStorage - */ - /* - if(typeof pJSON==='string'){ - if(window && !window.JSON){ - try{ - files=eval('('+pJSON+')'); - }catch(err){ - console.log(err); - } - } - else files=JSON.parse(pJSON); - }else - */ - files=pJSON; - /* сохраняем путь каталога в котором мы сейчас находимся*/ - var lPath=files[0].path; - - /* сохраняем путь */ - CloudFunc.Path=lPath; - - /* - * Строим путь каталога в котором мы находимся - * со всеми подкаталогами - */ - var lHtmlPath=CloudFunc._getDirPath(lPath); - - /* Убираем последний слэш - * с пути для кнопки обновить страницу - * если он есть - */ - var lRefreshPath=CloudFunc.removeLastSlash(lPath); - - /* путь в ссылке, который говорит - * что js отключен - */ - var lNoJS_s=CloudFunc.NOJS; - var lFS_s=CloudFunc.FS; - - var lFileTable='
  • '+ - ''+ - ''+ - '' + - ''+ - ''+ - ''+lHtmlPath+''+ - '
  • '; - - var fileTableTitles=['name','size','owner','mode']; - lFileTable+=CloudFunc._getFileTableHeader(fileTableTitles); - /* Если мы не в корне */ - if(lPath!=='/'){ - /* ссылка на верхний каталог*/ - var lDotDot; - /* убираем последний слеш и каталог в котором мы сейчас находимся*/ - lDotDot=lPath.substr(lPath,lPath.lastIndexOf('/')); - lDotDot=lDotDot.substr(lDotDot,lDotDot.lastIndexOf('/')); - /* Если предыдущий каталог корневой */ - if(lDotDot==='')lDotDot='/'; - - /* Сохраняем путь к каталогу верхнего уровня*/ - lFileTable += '
  • '+ - '' + - '' + - '' + - ''+".." + - '' + - '<dir>'+ - '.' + - '' + - '
  • '; - } - var lLength=files.length; - - for(var i=1;i'; - lFileTable +=''; - lFileTable +='' + - '16? - ' title="'+files[i].name+'">' + - files[i].name.substr( - files[i].name,16)+ - '..':'>'+files[i].name) + - "" + - ''; - /* если папка - не выводим размер */ - lFileTable +='' + - (files[i].size==='dir'? - '<dir>': - /* если это файл - получаем - * короткий размер - */ - CloudFunc.getShortedSize( - files[i].size)); - lFileTable +='' + - '' + - (!files[i].uid?'root':files[i].uid) + - '' + - '' + - /* конвертируем названия разрешений - * из числового формата в буквенный - * при этом корневой каталог не трогаем - * по скольку в нём и так всё уже - * установлено еще на сервере - */ - (//lPath==='/'?files[i].mode: - CloudFunc.convertPermissionsToSymbolic(files[i].mode)) + - ''; - lFileTable +=''; - } - - /* если клавиши назначены и - * мы в корневом каталоге и - * верхний файл еще не выделен - - * выделяем верхний файл - */ - if(pKeyBinded && lPath==='/'&& - lFileTable.indexOf('
  • ')<0){ - lFileTable=lFileTable.replace('
  • ','
  • '); - } - - - - return lFileTable; -}; - -/* - * Если мы на стороне сервера - - * прописываем экспортируемые функции - */ -try{ - if(exports){ - /* экспортируемые функции */ - exports.checkExtension = CloudFunc.checkExtension; - exports.buildFromJSON = CloudFunc.buildFromJSON; - exports.replaceSpaces = CloudFunc.replaceSpaces; - exports.setTitle = CloudFunc.setTitle; - exports.convertPermissions = CloudFunc.convertPermissions; - exports.getUserUIDsAndNames = CloudFunc.getUserUIDsAndNames; - - /* константы*/ - exports.Name = CloudFunc.NAME; - exports.NOJS = CloudFunc.NOJS; - exports.FS =CloudFunc.FS; - - console.log('cloudfunc.js loaded...'); - } -}catch(err){ - /* если мы на клиенте */ -} \ No newline at end of file diff --git a/cloudcmd1/lib/server/minify.js b/cloudcmd1/lib/server/minify.js deleted file mode 100644 index 556fd119..00000000 --- a/cloudcmd1/lib/server/minify.js +++ /dev/null @@ -1,274 +0,0 @@ -/* Модуль сжатия js-скриптов и css*/ - -/* функция сжимает js-скрипты - * и сохраняет их с именем .min.js - */ - -var fs = require('fs'); - -exports.jsScripts=function jsScripts(){ - 'use strict'; - - /* подключаем модуль uglify-js - * если его нет - дальнейшая - * работа функции не имеет смысла - */ - try{ - var jsp = require("uglify-js").parser; - var pro = require("uglify-js").uglify; - }catch(error){ - console.log('can\'n load uglify-js\n' + - 'to use js-minification you need to install uglify-js\n' + - 'npm install uglify-js\n' + - 'https://github.com/mishoo/UglifyJS'); - return false; - } - /* Константы */ - var CLIENT_JS='client.js'; - var CLOUDFUNC_JS='lib/cloudfunc.js'; - var CLIENT_KEYBINDING_JS='lib/client/keyBinding.js'; - - var dataReaded_f=function(pFileName, pData){ - console.log('file ' + pFileName + ' readed'); - - /*********************************/ - /* сжимаем код через uglify-js */ - var uglify_js=function(pDdata){ - var orig_code = pDdata.toString(); - var ast = jsp.parse(orig_code); // parse code and get the initial AST - ast = pro.ast_mangle(ast); // get a new AST with mangled names - ast = pro.ast_squeeze(ast); // get an AST with compression optimizations - var result_code = pro.gen_code(ast); // compressed code here - return result_code; - }; - /*********************************/ - var final_code=uglify_js(pData); - - var minFileName=pFileName.replace('.js','.min.js'); - /* если мы сжимаем client.js - - * меняем строку cloudfunc.js на - * cloudfunc.min.js и выводим сообщение - * - * меняем строку keyBinding.js на - * keyBinding.min.js - * если другой файл - ничего не деалем - */ - if(pFileName===CLIENT_JS) - console.log('file name of ' + - CLOUDFUNC_JS + - ' in ' + - CLIENT_JS + - ' changed. size:', - (final_code=final_code - .replace('cloudfunc.js','cloudfunc.min.js') - .replace('keyBinding.js','keyBinding.min.js')).length); - - /* записываем сжатый js-скрипт*/ - fs.writeFile(minFileName, final_code, fileWrited(minFileName)); - }; - console.log('reading file ' + CLIENT_JS+'...'); - fs.readFile(CLIENT_JS,fileReaded(CLIENT_JS,dataReaded_f)); - - console.log('reading file ' + CLOUDFUNC_JS+'...'); - fs.readFile(CLOUDFUNC_JS,fileReaded(CLOUDFUNC_JS,dataReaded_f)); - - console.log('reading file ' + CLIENT_KEYBINDING_JS+'...'); - fs.readFile(CLIENT_KEYBINDING_JS, fileReaded(CLIENT_KEYBINDING_JS,dataReaded_f)); - - - return true; -}; - -/* функция сжимает css-стили - * и сохраняет их с именем .min.css - * @pImgConvertToBase64_b - булевый признак, - * который отвечает за то, что быконвертировать - * картинки в base64 и поместить в выходной css файл - */ -exports.cssStyles=function cssStyles(pImgConvertToBase64_b){ - 'use strict'; - - /* connecting cleanCSS, - * if we can't find it - - * return false - */ - var cleanCSS; - try{ - cleanCSS = require('clean-css'); - }catch(error){ - console.log('can\'n load clean-css \n' + - 'to use css-minification you need to install clean-css \n' + - 'npm install clean-css\n' + - 'https://github.com/GoalSmashers/clean-css'); - return false; - } - - /* Константы */ - var STYLE_CSS='style.css'; - var RESET_CSS='reset.css'; - - var lAllStyle=''; - var lResetCssDone=false; - var lStyleCssDone=false; - var dataReaded_f=function(pFileName, pData){ - console.log('file ' + pFileName + ' readed'); - /*********************************/ - /* сжимаем код через clean-css */ - var clean_css=function(pData){ - /* Сохраняем весь стиль в одну переменную*/ - return cleanCSS.process(pData); - }; - /*********************************/ - var final_code=clean_css(pData); - - lAllStyle+=final_code; - - var minFileName=pFileName.replace('.css','.min.css'); - - if(pFileName===STYLE_CSS)lStyleCssDone=true; - if(pFileName===RESET_CSS)lResetCssDone=true; - /* if all files writed we - * save all minimized css - * to one file all.min.css - */ - /* если включена конвертация картинок в base64 - * вызываем её - */ - if(lStyleCssDone && lResetCssDone) - if(pImgConvertToBase64_b) - base64_images(lAllStyle); - else - fs.writeFile('all.min.css', lAllStyle, fileWrited('all.min.css')); - - /* записываем сжатый css файл*/ - else fs.writeFile(minFileName, final_code, fileWrited(minFileName)); - }; - - console.log('reading file ' + STYLE_CSS+'...'); - fs.readFile(STYLE_CSS,fileReaded(STYLE_CSS,dataReaded_f)); - - console.log('reading file ' + RESET_CSS+'...'); - fs.readFile(RESET_CSS,fileReaded(RESET_CSS,dataReaded_f)); - - return true; -}; - -/* функция сжимает css-стили - * и сохраняет их с именем .min.css - */ -exports.html=function(){ - 'use strict'; - - /* connecting cleanCSS, - * if we can't find it - - * return false - */ - var htmlMinifier; - try{ - htmlMinifier = require('html-minifier'); - }catch(error){ - console.log('can\'n load html-minifier \n' + - 'to use html-minification you need to install html-minifier\n' + - 'npm install html-minifier\n' + - 'https://github.com/kangax/html-minifier'); - return false; - } - - /* Константы */ - var INDEX_HTML='index.html'; - - var dataReaded_f=function(pFileName, pData){ - console.log('file ' + pFileName + ' readed'); - /*********************************/ - /* сжимаем код через clean-css */ - var html_minify=function(pData){ - /* Сохраняем весь стиль в одну переменную*/ - - var lOptions={ - removeComments: true, - removeCommentsFromCDATA: true, - removeCDATASectionsFromCDATA: true, - collapseWhitespace: true, - collapseBooleanAttributes: true, - removeAttributeQuotes: true, - removeRedundantAttributes: true, - useShortDoctype: true, - removeEmptyAttributes: true, - /* оставляем, поскольку у нас - * в элемент fm генерируеться - * таблица файлов - */ - removeEmptyElements: false, - removeOptionalTags: true, - removeScriptTypeAttributes: true, - removeStyleLinkTypeAttributes: true - }; - - - return htmlMinifier.minify(pData,lOptions); - }; - /*********************************/ - var final_code=html_minify(pData); - - var minFileName=pFileName.replace('.html','.min.html'); - - /* записываем сжатый html файл*/ - fs.writeFile(minFileName, final_code, fileWrited(minFileName)); - }; - - console.log('reading file ' + INDEX_HTML+'...'); - fs.readFile(INDEX_HTML,fileReaded(INDEX_HTML,dataReaded_f)); - - return true; -}; - -/* функция переводит картинки в base64 и записывает в css-файл*/ -function base64_images(pFileContent_s){ - 'use strict'; - var b64img; - try{ - b64img = require('css-b64-images'); - }catch(error){ - console.log('can\'n load clean-css \n' + - 'to use images to base64 convertation you need to install css-base64-images \n' + - 'npm install -g css-b64-images\n' + - 'https://github.com/Filirom1/css-base64-images'); - return false; - } - b64img.fromString(pFileContent_s, '.','', function(err, css){ - fs.writeFile('all.min.css', css, fileWrited('all.min.css')); - }); -} - -/* Функция создаёт асинхроную версию - * для чтения файла - * @pFileName - имя считываемого файла - */ -function fileReaded(pFileName,pCompressFunc){ - "use strict"; - return function(pError,pData){ - /* функция в которую мы попадаем, - * если данные считались - * - * если ошибка - показываем её - * иначе если переданная функция - - * функция запускаем её - */ - if(!pError) - if (pCompressFunc && typeof pCompressFunc==="function") - pCompressFunc(pFileName,pData.toString()); - else console.log(pError); - }; -} - -/* - * Функция вызываеться после записи файла - * и выводит ошибку или сообщает, - * что файл успешно записан - */ -function fileWrited(pFileName){ - "use strict"; - return function(error){ - console.log(error?error:('file '+pFileName+' writed...')); - }; -} \ No newline at end of file diff --git a/cloudcmd1/node_modules/.bin/jitsu b/cloudcmd1/node_modules/.bin/jitsu deleted file mode 120000 index ab860a6f..00000000 --- a/cloudcmd1/node_modules/.bin/jitsu +++ /dev/null @@ -1 +0,0 @@ -../jitsu/bin/jitsu \ No newline at end of file diff --git a/cloudcmd1/node_modules/.bin/nodester b/cloudcmd1/node_modules/.bin/nodester deleted file mode 120000 index aa4a5eb1..00000000 --- a/cloudcmd1/node_modules/.bin/nodester +++ /dev/null @@ -1 +0,0 @@ -../nodester-cli/bin/nodester.js \ No newline at end of file diff --git a/cloudcmd1/node_modules/jitsu b/cloudcmd1/node_modules/jitsu deleted file mode 120000 index d5540629..00000000 --- a/cloudcmd1/node_modules/jitsu +++ /dev/null @@ -1 +0,0 @@ -../../local/lib/node_modules/jitsu \ No newline at end of file diff --git a/cloudcmd1/node_modules/nodester-cli b/cloudcmd1/node_modules/nodester-cli deleted file mode 120000 index da254801..00000000 --- a/cloudcmd1/node_modules/nodester-cli +++ /dev/null @@ -1 +0,0 @@ -../../local/lib/node_modules/nodester-cli \ No newline at end of file diff --git a/cloudcmd1/package.json b/cloudcmd1/package.json deleted file mode 100644 index 4bcf5c47..00000000 --- a/cloudcmd1/package.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "name": "cloudcmd1", - "version": "0.0.1-10", - "scripts": { - "start": "server.js" - }, - "engines": { - "node": "0.6.x" - }, - "subdomain": "cloudcmd1", - "dependencies": { - "uglify-js": "*", - "html-minifier": "*", - "clean-css": "*" - } -} diff --git a/cloudcmd1/package2.json b/cloudcmd1/package2.json deleted file mode 100644 index f2d59387..00000000 --- a/cloudcmd1/package2.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "name": "cloudcmd", - "version": "0.0.1-3", - "scripts": { - - "start": "server.js" - }, - "engines": { - "node": "0.6.x" - }, - "subdomain": "cloudcmd" -} diff --git a/cloudcmd1/reset.css b/cloudcmd1/reset.css deleted file mode 100644 index a24c865b..00000000 --- a/cloudcmd1/reset.css +++ /dev/null @@ -1,100 +0,0 @@ -/* ============================================================================= - HTML5 display definitions - ========================================================================== */ - -/* -article, aside, details, figcaption, figure, footer, header, hgroup, nav, section { display: block; } -audio, canvas, video { display: inline-block; *display: inline; *zoom: 1; } -audio:not([controls]) { display: none; } -[hidden] { display: none; } -*/ - -/* ============================================================================= - Base - ========================================================================== */ - -/* - * 1. Correct text resizing oddly in IE6/7 when body font-size is set using em units - * 2. Prevent iOS text size adjust on device orientation change, without disabling user zoom: h5bp.com/g - */ - -html { font-size: 100%; -webkit-text-size-adjust: 100%; -ms-text-size-adjust: 100%; font-family: sans-serif; color: #222;} -body { margin: 0; font-size: 1em; line-height: 1.4; } - -/* - * Remove text-shadow in selection highlight: h5bp.com/i - * These selection declarations have to be separate - * Also: hot pink! (or customize the background color to match your design) - */ -/* -::-moz-selection { background: #fe57a1; color: #fff; text-shadow: none; } - ::selection { background: #fe57a1; color: #fff; text-shadow: none; } -*/ -::selection { text-shadow: none; opacity: 0;} - - -/* ============================================================================= - Links - ========================================================================== */ - -a {text-decoration:none; color: #00e; } -a:visited { color: #551a8b; } -a:hover { color: #06e; } -a:focus { outline: thin dotted; } - -/* Improve readability when focused and hovered in all browsers: h5bp.com/h */ -a:hover, a:active { outline: 0; } - -ul{ margin: 1em 0; padding: 0 0 0 40px; } - -/* - * 1. Display hand cursor for clickable form elements - * 2. Allow styling of clickable form elements in iOS - * 3. Correct inner spacing displayed oddly in IE7 (doesn't effect IE6) - */ - - -/* ============================================================================= - Chrome Frame Prompt - ========================================================================== */ - -.chromeframe { margin: 0.2em 0; background: #ccc; color: black; padding: 0.2em 0; } - - -/* ==|== non-semantic helper classes ======================================== - Please define your styles before this section. - ========================================================================== */ - -/* For image replacement */ -.ir { display: block; border: 0; text-indent: -999em; overflow: hidden; background-color: transparent; background-repeat: no-repeat; text-align: left; direction: ltr; *line-height: 0; } -.ir br { display: none; } - -/* Hide from both screenreaders and browsers: h5bp.com/u */ -.hidden { display: none !important; visibility: hidden; } - -/* Hide only visually, but have it available for screenreaders: h5bp.com/v */ -.visuallyhidden { border: 0; clip: rect(0 0 0 0); height: 1px; margin: -1px; overflow: hidden; padding: 0; position: absolute; width: 1px; } - -/* Extends the .visuallyhidden class to allow the element to be focusable when navigated to via the keyboard: h5bp.com/p */ -.visuallyhidden.focusable:active, .visuallyhidden.focusable:focus { clip: auto; height: auto; margin: 0; overflow: visible; position: static; width: auto; } - -/* Hide visually and from screenreaders, but maintain layout */ -.invisible { visibility: hidden; } - -/* Contain floats: h5bp.com/q */ -.clearfix:before, .clearfix:after { content: ""; display: table; } -.clearfix:after { clear: both; } -.clearfix { *zoom: 1; } - -/* ==|== print styles ======================================================= - Print styles. - Inlined to avoid required HTTP connection: h5bp.com/r - ========================================================================== */ - -@media print { - * { background: transparent !important; color: black !important; box-shadow:none !important; text-shadow: none !important; filter:none !important; -ms-filter: none !important; } /* Black prints faster: h5bp.com/s */ - a, a:visited { text-decoration: underline; } - a[href]:after { content: " (" attr(href) ")"; } - .ir a:after, a[href^="javascript:"]:after, a[href^="#"]:after { content: ""; } /* Don't show links for images, or javascript/internal links */ - @page { margin: 0.5cm; } -} \ No newline at end of file diff --git a/cloudcmd1/server.js b/cloudcmd1/server.js deleted file mode 100644 index 2839b1ef..00000000 --- a/cloudcmd1/server.js +++ /dev/null @@ -1,635 +0,0 @@ -"use strict"; - -/* Обьект содержащий все функции и переменные - * серверной части Cloud Commander'а - */ -var CloudServer={ - /* функция, которая генерирует заголовки - * файлов, отправляемые сервером клиенту - */ - generateHeaders :function(){}, - /* функция высылает - * данные клиенту - */ - sendResponse :function(){}, - /* Структура содержащая функции, - * и переменные, в которых - * говориться о поддерживаемых - * браузером технологиях - */ - BrowserSuport :{}, - /* Обьект для работы с кэшем */ - Cashe :{}, - /* Обьект через который - * выполняеться сжатие - * скриптов и стилей - */ - Minify :{}, - /* Асоциативный масив обьектов для - * работы с ответами сервера - * высылаемыми на запрос о файле и - * хранащий информацию в виде - * Responces[name]=responce; - */ - Responses :{}, - - /* ПЕРЕМЕННЫЕ */ - /* Поддержка браузером JS*/ - NoJS :true, - /* Поддержка gzip-сжатия - * браузером - */ - Gzip :undefined, - - /* КОНСТАНТЫ */ - /* index.html */ - INDEX :'index.html', - /* name of direcotory with libs */ - LIBDIR :'./lib', - LIBDIRSERVER :'./lib/server' -}; - -/* - * Обьект для работы с кэшем - * аналог клиентского обьекта - * с тем отличием, что в нём - * будут храниться серверные - * данные, такие как файлы - * отдаваемые клиенту - * (файлы проэкта по большому - * счёту, для ускорения - * первичной загрузки) - */ -CloudServer.Cache={ - _allowed :true, /* приватный переключатель возможности работы с кэшем */ - /* данные в которых храняться файлы - * в формате <поле> : <значение> - * _data[name]=pData; - * одному имени соответствуют - * одни данные - */ - _data :{}, - - /* функция говорит можно ли работать с кэшем */ - isAllowed :(function(){ - return CloudServer.Cache._allowed; - }), - /* функция устанавливает возможность работать с кэшем */ - setAllowed :(function(pAllowed){ - CloudServer.Cache._allowed=pAllowed; - }), - /* Если доступен кэш - * сохраняем в него данные - */ - set :(function(pName, pData){ - if(CloudServer.Cache._allowed && pName && pData){ - CloudServer.Cache._data[pName]=pData; - } - }), - /* Если доступен Cache принимаем из него данные*/ - get :(function(pName){ - if(CloudServer.Cache._allowed && pName){ - return CloudServer.Cache._data[pName]; - } - else return null; - }), - - /* Функция очищает кэш*/ - clear :(function(){ - if(CloudServer.Cache._allowed){ - CloudServer.Cache._data={}; - } - }) -}; - -/* Обьект для сжатия скриптов и стилей - * по умолчанию - сжимаються - */ -CloudServer.Minify={ - /* приватный переключатель минимизации */ - _allowed :{css:true,js:true,html:true, img: true}, - - /* функция разрешает или - * запрещает минимизировать - * css/js/html - * @pAllowed: - структура, в которой - * передаються параметры - * минификации, вида - * {js:true,css:true,html:false; img:true} - * img отвечает за перевод картинок в base64 - * и сохранение их в css-файл - */ - setAllowed :(function(pAllowed){ - if(pAllowed){ - this._allowed.css=pAllowed.css; - this._allowed.js=pAllowed.js; - this._allowed.html=pAllowed.html; - this._allowed.img=pAllowed.img; - } - }), - - /* - * Функция минимизирует css/js/html - * если установлены параметры минимизации - */ - doit :(function(){ - if(this._allowed.css || - this._allowed.js || - this._allowed.html){ - var lMinify = require(CloudServer.LIBDIRSERVER+'/minify'); - - this.done.js=this._allowed.js?lMinify.jsScripts():false; - this.done.html=this._allowed.html?lMinify.html():false; - this.done.css=this._allowed.css?lMinify.cssStyles(this._allowed.img):false; - } - }), - /* свойство показывающее случилась ли ошибка*/ - done:{js: false,css: false, html:false} -}; - - -var LeftDir='/'; -var RightDir=LeftDir; -/* - var Path = require('path'); -*/ /* модуль для работы с путями*/ - -var Fs = require('fs'); /* модуль для работы с файловой системой*/ - -var Zlib; -/* node v0.4 not contains zlib - */ -try{ - Zlib = require('zlib'); /* модуль для сжатия данных gzip-ом*/ -}catch(error){ - Zlib=undefined; - console.log('to use gzip-commpression' + - 'you should install zlib module\n' + - 'npm install zlib'); -} -var CloudFunc = require(CloudServer.LIBDIR + - (CloudServer.Minify.done.js?/* если стоит минификация*/ - '/cloudfunc.min':/* добавляем сжатый - иначе обычный */ - '/cloudfunc')); /* модуль с функциями */ -/* конструктор*/ -CloudServer.init=(function(){ - /* Переменная в которой храниться кэш*/ - CloudServer.Cache.setAllowed(true); - /* Change default parameters of - * js/css/html minification - */ - CloudServer.Minify.setAllowed({ - js:true, - css:true, - html:true, - img:true - }); - /* Если нужно минимизируем скрипты */ - CloudServer.Minify.doit(); -}); - - -/* создаём сервер на порту 31337*/ -CloudServer.start=function() -{ - CloudServer.init(); - - var http = require('http'); - http.createServer(CloudServer._controller).listen(process.env.PORT || - process.env.VCAP_APP_PORT /* cloudfoundry */ || - 31337, - '0.0.0.0' || '127.0.0.1'); - console.log('Cloud Commander server running at http://127.0.0.1:'+ - (process.env.PORT===undefined?31337:process.env.PORT)); -}; - - -/* Функция создаёт заголовки файлов - * в зависимости от расширения файла - * перед отправкой их клиенту - * @pName - имя файла - * @pGzip - данные сжаты gzip'ом - */ -CloudServer.generateHeaders = function(pName, pGzip){ - var lType=''; - /* высылаем заголовок в зависимости от типа файла */ - /* если расширение у файла css - - * загружаем стили - */ - if(CloudFunc.checkExtension(pName,'css')) - lType='text/css'; - /* загружаем js */ - else if(CloudFunc.checkExtension(pName,'js')) - lType='text/javascript'; - /* загружаем картинки*/ - else if(CloudFunc.checkExtension(pName,'png')) - lType='image/png'; - /* загружаем json*/ - else if(CloudFunc.checkExtension(pName,'json')) - lType='application/json'; - else if(CloudFunc.checkExtension(pName,'html')) - lType='text/html'; - else if(CloudFunc.checkExtension(pName,'appcache')) - lType='text/cache-manifest'; - /* если это неизвестный тип файла - - * высылаем его просто как текст - */ - else lType='text/plain'; - - return { - /* if type of file any, but img - - * then we shoud specify charset - */ - 'Content-Type': lType + (lType.indexOf('img')<0?'; charset=UTF-8':''), - 'cache-control': 'max-age='+(31337*21), - 'last-modified': new Date().toString(), - 'content-encoding': pGzip?'gzip':'', - /* https://developers.google.com/speed/docs/best-practices/caching?hl=ru#LeverageProxyCaching */ - 'Vary': 'Accept-Encoding' - }; -}; - -/* - * Главная функция, через которую проихсодит - * взаимодействие, обмен данными с клиентом - * @req - запрос клиента (Request) - * @res - ответ сервера (Response) - */ -CloudServer._controller=function(pReq, pRes) -{ - /* Читаем содержимое папки, - переданное в url - */ - var url = require("url"); - var pathname = url.parse(pReq.url).pathname; - console.log('pathname: '+pathname); - - /* получаем поддерживаемые браузером кодировки*/ - var lAcceptEncoding = pReq.headers['accept-encoding']; - /* запоминаем поддерживает ли браузер - * gzip-сжатие при каждом обращении к серверу - * и доступен ли нам модуль zlib - */ - if (lAcceptEncoding && - lAcceptEncoding.match(/\bgzip\b/) && - Zlib){ - CloudServer.Gzip=true; - }else - CloudServer.Gzip=false; - /* путь в ссылке, который говорит - * что js отключен - */ - var lNoJS_s=CloudFunc.NOJS; - var lFS_s=CloudFunc.FS; - - if(pathname!=='/favicon.ico') - { - console.log("request for " + pathname + " received..."); - var lName; - - /* если в пути нет информации ни о ФС, - * ни об отсутствии js, - * ни о том, что это корневой - * каталог - загружаем файлы проэкта - */ - if(pathname.indexOf(lFS_s)<0 && - pathname.indexOf(lNoJS_s)<0 && - pathname!=='/'){ - /* если имена файлов проекта - загружаем их*/ - /* убираем слеш и читаем файл с текущец директории*/ - //lName=Path.basename(pathname); - - /* добавляем текующий каталог к пути */ - lName='.'+pathname; - console.log('reading '+lName); - /* сохраняем указатель на responce и имя */ - CloudServer.Responses[lName]=pRes; - - /* Берём значение из кэша - * сжатый файл - если gzip-поддерживаеться браузером - * не сжатый - в обратном случае - */ - var lFileData=CloudServer.Cache.get(CloudServer.Gzip?(lName+'_gzip'):lName); - - var lReadFileFunc_f=CloudServer.getReadFileFunc(lName); - /* если там что-то есть передаём данные в функцию - * readFile - */ - if(lFileData){ - console.log('readed from cache'); - /* передаём данные с кэша, - * если gzip включен - сжатые - * в обратном случае - несжатые - */ - lReadFileFunc_f(undefined,lFileData,true); - } - else Fs.readFile(lName,lReadFileFunc_f); - - }else{/* если мы имеем дело с файловой системой*/ - /* если путь не начинаеться с no-js - значит - * js включен - */ - /* убираем пометку cloud, без которой c9.io - * не работает поскольку путь из двух слешей - * (/fs/no-js/) - очень короткий, нужно - * длиннее - */ - - if(pathname.indexOf(lNoJS_s)!==lFS_s.length && pathname!=='/'){ - CloudServer.NoJS=false; - }else pathname=pathname.replace(lNoJS_s,''); - - /* убираем индекс файловой системы */ - if(pathname.indexOf(lFS_s)===0){ - pathname=pathname.replace(lFS_s,''); - /* если посетитель только зашел на сайт - * no-js будет пустым, как и fs - */ - /* если в пути нету fs - посетитель только зашел на сайт - * загружаем его полностью. - */ - }else CloudServer.NoJS=true; - /* если в итоге путь пустой - * делаем его корневым - */ - if(pathname==='')pathname='/'; - - RightDir=pathname; - LeftDir=pathname; - - /* если встретиться пробел - - * меня код символа пробела на пробел - */ - - LeftDir=CloudFunc.replaceSpaces(LeftDir); - RightDir=CloudFunc.replaceSpaces(RightDir); - - /* Проверяем с папкой ли мы имеем дело */ - - /* читаем сновные данные о файле */ - var lStat; - try{ - lStat=Fs.statSync(LeftDir); - }catch(error){ - console.log(error); - CloudServer.Responses[LeftDir]=pRes; - CloudServer.sendResponse('OK',error.toString(),LeftDir); - } - /* если это каталог - - * читаем его содержимое - */ - try{ - /* если установлено сжатие - * меняем название html-файла и - * загружаем сжатый html-файл в дальнейшем - */ - CloudServer.INDEX=(CloudServer.Minify.done.html?'index.min.html':CloudServer.INDEX); - /* - * сохраним указатель на response - */ - CloudServer.Responses[CloudServer.INDEX]=pRes; - if(lStat.isDirectory()) - Fs.readdir(LeftDir,CloudServer._readDir); - /* отдаём файл */ - else if(lStat.isFile()){ - CloudServer.Responses[LeftDir]=pRes; - Fs.readFile(LeftDir,CloudServer.getReadFileFunc(LeftDir)); - console.log('reading file: '+LeftDir); - } - }catch(error){console.log(error);} - } - } -}; - -/* Функция читает ссылку или выводит информацию об ошибке*/ -CloudServer._readDir=function (pError, pFiles) -{ - if(!pError) - { - /* данные о файлах в формате JSON*/ - var lJSON=[]; - var lJSONFile={}; - /* Если мы не в корне добавляем слеш к будующим ссылкам */ - if(LeftDir!=='/') - { - RightDir+='/'; - LeftDir+='/'; - } - - pFiles=pFiles.sort(); - - lJSON[0]={path:LeftDir,size:'dir'}; - var fReturnFalse=function returnFalse(){return false;}; - for(var i=0;i','') - .replace('style.css','all.min.css') - :lIndex; - - lIndex = CloudServer.Minify.done.js?lIndex.replace('client.js','client.min.js'):lIndex; - - lIndex=lIndex.toString().replace('
    ','
    '+lList); - /* меняем title */ - lIndex=lIndex.replace('Cloud Commander', - ''+CloudFunc.setTitle()+''); - /* отображаем панель быстрых клавишь */ - lList=lIndex; - /* если браузер поддерживает gzip-сжатие*/ - lHeader=CloudServer.generateHeaders('text/html',CloudServer.Gzip); - }catch(error){console.log(error);} - }else{ - /* в обычном режиме(когда js включен - * высылаем json-структуру файлов - * с соответствующими заголовками - */ - lList=JSON.stringify(lJSON); - lHeader=CloudServer.generateHeaders('application/json',CloudServer.Gzip); - } - /* если браузер поддерживает gzip-сжатие - сжимаем данные*/ - if(CloudServer.Gzip){ - Zlib.gzip(lList,CloudServer.getGzipDataFunc(lHeader,CloudServer.INDEX)); - } - /* если не поддерживаеться - отсылаем данные без сжатия*/ - else - CloudServer.sendResponse(lHeader,lList,CloudServer.INDEX); - } - else - { - console.log(pError); - CloudServer.sendResponse('OK',pError.toString()); - } -}; - -/* Функция генерирует функция считывания файла - * таким образом, что бы у нас было - * имя считываемого файла - * @pName - полное имя файла - */ -CloudServer.getReadFileFunc = function(pName){ -/* - * @pError - ошибка - * @pData - данные - * @pFromFile - прочитано с файла bool - */ - var lReadFile=function(pError,pData,pFromCache_b){ - if (!pError){ - console.log('file ' + pName + ' readed'); - - /* берём из кэша данные файла - * если их нет в кэше - - * сохраняем - */ - if(!pFromCache_b && CloudServer.Cache.isAllowed) - CloudServer.Cache.set(pName,pData); - /* если кэш есть - * сохраняем его в переменную - * которая до этого будет пустая - * по скольку мы будем вызывать этот метод - * сами, ведь файл уже вычитан - */ - - var lHeader=CloudServer.generateHeaders(pName,CloudServer.Gzip); - /* если браузер поддерживает gzip-сжатие - сжимаем данные*/ - if(CloudServer.Gzip &&!pFromCache_b){ - /* сжимаем содержимое */ - Zlib.gzip(pData,CloudServer.getGzipDataFunc(lHeader,pName)); - } - else{ - /* высылаем несжатые данные */ - CloudServer.sendResponse(lHeader,pData,pName); - } - } - else - { - console.log(pError.path); - if(pError.path!=='passwd.json') - { - console.log(pError); - CloudServer.sendResponse('OK',pError.toString()); - }else{ - CloudServer.sendResponse('OK','passwd.json'); - } - } - }; - return lReadFile; -}; - -/* Функция получает сжатые данные - * @pHeader - заголовок файла - */ -CloudServer.getGzipDataFunc=function(pHeader,pName){ - return function(error,pResult){ - if(!error){ - /* отправляем сжатые данные - * вместе с заголовком - */ - /* если установлена работа с кэшем - * сохраняем сжатые данные - */ - if(CloudServer.Cache.isAllowed){ - /* устанавливаем кєш */ - console.log(pName+' gziped'); - CloudServer.Cache.set(pName+'_gzip',pResult); - } - CloudServer.sendResponse(pHeader,pResult,pName); - } - else{ - console.log(error); - CloudServer.sendResponse(pHeader,error); - } - }; -}; -/* Функция высылает ответ серверу - * @pHead - заголовок - * @pData - данные - * @pName - имя отсылаемого файла - */ -CloudServer.sendResponse = function(pHead, pData,pName){ - /* если у нас есть указатель на responce - * для соответствующего файла - - * высылаем его - */ - var lResponse=CloudServer.Responses[pName]; - if(lResponse){ - lResponse.writeHead(200,pHead); - lResponse.end(pData); - console.log(pName+' sended'); - } -}; - -CloudServer.start(); \ No newline at end of file diff --git a/cloudcmd1/style.css b/cloudcmd1/style.css deleted file mode 100644 index 57136168..00000000 --- a/cloudcmd1/style.css +++ /dev/null @@ -1,317 +0,0 @@ -/* -@import url(//fonts.googleapis.com/css?family=Droid+Sans+Mono); -*/ - -/* Foundation Icons General Enclosed */ -@font-face { - font-family: 'FoundationIconsGeneralEnclosed'; - src: url('//dl.dropbox.com/u/78163899/mnemonia/fonts/foundation-icons-general-enclosed.woff') format('woff'); - font-weight: normal; - font-style: normal; - -} -/* символьный шрифт от гитхаба*/ -@font-face { - font-family: 'Octicons Regular'; - font-style: normal; - font-weight: normal; - src: local('Octicons Regular'), url('//dl.dropbox.com/u/78163899/mnemonia/fonts/octicons-regular-webfont.woff') format('woff'); -} - -@font-face { - font-family: 'Droid Sans Mono'; - font-style: normal; - font-weight: normal; - src: local('Droid Sans Mono'), local('DroidSansMono'), url('http://themes.googleusercontent.com/static/fonts/droidsansmono/v4/ns-m2xQYezAtqh7ai59hJUYuTAAIFFn5GTWtryCmBQ4.woff') format('woff'); -} - -body{ - font:16px "Droid Sans Mono"; -} - -.menu{ - font: 16px 'Octicons Regular'; - margin-bottom: 0; -} - -.path_icon{ - font-family:'FoundationIconsGeneralEnclosed'; - font-size:30px; - color: #46A4C3;/*#55BF3F; green*/ - text-shadow:black 0 2px 1px; - /* размер иконки и позиция на png-файле*/ - width: 15px; - height: 15px; - display: inline-block; - position: relative; - top: 3px; - left: -4px; -} -.path_icon:hover{ - /* - color:#45D827; - */ - cursor:pointer; -} -.path_icon:active{ - text-shadow:black 0 0 1px; - position: relative; - top: 4px; -} -.icon{ - font-family: 'Octicons Regular'; - font-size:16px; - width:16px; - height:16px; - display:inline-block; - margin-left:0.5%; -} -.error::before{ - content:'\f026'; - cursor:default; - color:rgb(222, 41, 41); - position: relative; - top: -3px; -} -.loading{ - background:url(/img/spinner.gif); - position:relative; - top:1px; -} -.error:hover{ - color:rgba(222, 41, 41, 0.81); -} -.refresh-icon{ - background:url(/img/panel_refresh.png) no-repeat; -} -.refresh-icon:active{ - /*background-position-y: -15px;*/ -background:url(/img/panel_refresh.png) 0 -15px no-repeat; -} -.clear-cache{ - background:url(/img/console_clear.png) -4px -4px no-repeat; - margin-right: 6px; - margin-left: 7px; -} -.clear-cache:active{ - /* - background-position-y: -25px; - */ - top:5px; -} - -.settings:before{ - content:'k'; -} -.links{ - color:red; - } - -.mini-icon { - float: left; - height: 16px; - left: -5px; - margin-left: 6px; - position: relative; - top: 2px; - width: 16px; - /* отступ перед картинкой - * для нормального отображения - * рамки - */ -} -/* freeupex */ -.directory{ - /*list-style-image*/ - background-image:url('/img/dir.png'); - background-repeat: no-repeat; - background-position: 0 0; -} -.text-file{ - /*list-style-image*/ - background-image:url('/img/txt.png'); - background-repeat: no-repeat; - background-position: 0 0; -} -#fm{ - height:90%; - overflow-y: scroll; -} -.fm_header{ - font-weight: bold; -} -#path{ - margin-left:1.5%; -} -#left{ - float:left; - width:90%; -} -/* фон файла, на котором курсор*/ -.current-file{ - border: 2px solid rgba(49, 123, 249, .40); -} -.selected-file{ - background-color: rgba(49, 123, 249, .40); - color:white; -} -#right{ - float:right; -} -.panel{ - display: table; - width:45%; -} -#keyspanel{ - text-align: center; -} -/* информация о файлах и папках*/ -.name{ - float: left; - width: 37%; -} -.size{ - float:left; - width:16%; - /* Ставим выравнивание, - * что бы размер был в - * одной ровной колонке - */ - text-align: right; - /* Ставим отступ, что бы - * size не налазил на uid - * (owner) - */ - margin-right: 27px; -} -.owner{ -} -.mode{ - float: right; - width: 25%; -} - -ul,li{list-style-type:none;} -button{ - width:10%; -} -a{ - text-decoration:none; -} -a:hover, a:active { cursor:pointer;outline: 0; color: #06e; } -a:focus { outline: thin dotted; } - -/* Если размер окна очень маленький - * располагаем имя и атрибуты файла - * друг-под-другом -*/ -/* responsive design */ -@media only screen and (max-width: 600px){ - #left{ - width:90% !important; - } - .panel >li{ - margin:10px; - } - /* если правая панель не помещаеться - прячем её */ - #right{ - display:none; - } - /* текущий файл под курсором */ -.current-file{ - background-color: rgba(49, 123, 249, .40); - color:white; - } - /* делаем иконки под курсом белыми*/ -.current-file > .mini-icon{ - color:white; - } -.current-file > .text-file::before{ - color:white; - } - -/* меняем иконки на шрифтовые*/ - .mini-icon { - font: 60px 'Octicons Regular'; - width: 40%; - height: 0; - margin-left: 0; - float: right; - position: relative; - top: -17px; - - color: rgba(246, 224, 124, 0.56); - } - .directory::before{ - content: '\f216'; - } - .text-file::before{ - color: rgba(26, 224, 124, 0.56); - content: '\f211'; - } - .text-file{ - background-image:none; - } - - - - /* убираем заголовок*/ - .fm_header{ - display:none; - } - .mode,.size,.owner{ - /* располагаем элементы - * один под другим - */ - display: table; - float: none; - width: 0; - - text-align: left; - } - /* выводим заголовки рядом с полями */ - .name::before{ - content: 'name:'; - font-weight: bold; - font-size: 13px; - } - .mode::before{ - content: 'mode:'; - font-weight: bold; - font-size: 13px; - } - .size::before{ - content: 'size:'; - font-weight: bold; - font-size: 13px; - } - .owner::before{ - content: 'owner:'; - font-weight: bold; - font-size: 13px; - } - - .name{ - float: none; - width:100%; - font-size: 18px; - } -} -@media only screen and (min-width: 601px) and (max-width: 767px){ - #left{ - width:90% !important; - } - #right{ - display:none; - } -} - -@media only screen and (min-width:767px) and (max-width: 1060px){ - #left{ - width:90% !important; - } - /* если правая панель не помещаеться - прячем её */ - #right{ - display:none; - } -} \ No newline at end of file diff --git a/cloudcmd1/test.sh b/cloudcmd1/test.sh deleted file mode 100644 index 6b68a51f..00000000 --- a/cloudcmd1/test.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh -npm i -g jshint -echo "jshint server.js client.js lib/cloudfunc.js" -jshint --config ./.jshintrc ./server.js ./client.js ./lib/cloudfunc.js \ No newline at end of file diff --git a/package2.json b/package2.json deleted file mode 100644 index f2d59387..00000000 --- a/package2.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "name": "cloudcmd", - "version": "0.0.1-3", - "scripts": { - - "start": "server.js" - }, - "engines": { - "node": "0.6.x" - }, - "subdomain": "cloudcmd" -} diff --git a/package_was.json b/package_was.json deleted file mode 100644 index 5c67dd25..00000000 --- a/package_was.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "name": "cloudcmd", - "version": "0.0.1-9", - "scripts": { - "start": "server.js" - }, - "engines": { - "node": "0.6.x" - }, - "subdomain": "cloudcmd" -} \ No newline at end of file From 619e8bbb42c12ded2d86719b0fba58952036e472 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Thu, 5 Jul 2012 04:06:19 -0400 Subject: [PATCH 31/32] cleanup --- .gitignore | 1 - README.md | 53 --- client.js | 713 ------------------------------------- config.json | 9 - css/reset.css | 90 ----- css/style.css | 318 ----------------- img/console_clear.png | Bin 1344 -> 0 bytes img/dir.png | Bin 537 -> 0 bytes img/panel_refresh.png | Bin 872 -> 0 bytes img/spinner.gif | Bin 1569 -> 0 bytes img/txt.png | Bin 294 -> 0 bytes index.html | 54 --- lib/README.md | 5 - lib/client/keyBinding.js | 248 ------------- lib/cloudfunc.js | 504 -------------------------- lib/server/minify.js | 279 --------------- node_modules/.bin/jitsu | 1 - node_modules/.bin/nodester | 1 - node_modules/jitsu | 1 - node_modules/nodester-cli | 1 - node_modules/vcap | 1 - package.json | 13 - server.js | 684 ----------------------------------- test/test.sh | 6 - 24 files changed, 2982 deletions(-) delete mode 100644 .gitignore delete mode 100644 README.md delete mode 100644 client.js delete mode 100644 config.json delete mode 100644 css/reset.css delete mode 100644 css/style.css delete mode 100644 img/console_clear.png delete mode 100644 img/dir.png delete mode 100644 img/panel_refresh.png delete mode 100644 img/spinner.gif delete mode 100644 img/txt.png delete mode 100644 index.html delete mode 100644 lib/README.md delete mode 100644 lib/client/keyBinding.js delete mode 100644 lib/cloudfunc.js delete mode 100644 lib/server/minify.js delete mode 120000 node_modules/.bin/jitsu delete mode 120000 node_modules/.bin/nodester delete mode 120000 node_modules/jitsu delete mode 120000 node_modules/nodester-cli delete mode 120000 node_modules/vcap delete mode 100644 package.json delete mode 100644 server.js delete mode 100644 test/test.sh diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 029a5e87..00000000 --- a/.gitignore +++ /dev/null @@ -1 +0,0 @@ -.nodester.appconfig diff --git a/README.md b/README.md deleted file mode 100644 index fc55b9af..00000000 --- a/README.md +++ /dev/null @@ -1,53 +0,0 @@ -Cloud Commander [![Build Status](https://secure.travis-ci.org/coderaiser/cloudcmd.png?branch=master)](http://travis-ci.org/coderaiser/cloudcmd) -=============== -**Cloud Commander** - two-panels file manager, totally writed on js. -View [demo](http://demo-cloudcmd.cloudfoundry.com/ "demo"), [mirror](http://cloudcmd.nodester.com/ "mirror"). - -Google PageSpeed Score : [100](https://developers.google.com/speed/pagespeed/insights#url=http_3A_2F_2Fdemo-cloudcmd.cloudfoundry.com_2F&mobile=false "score") (out of 100). - -Benefits ---------------- -- full browser compatibility *(ie6+,chrome,safari,opera,firefox)*; -- responsible design -- one full page loading, *and then just one-time json-dir-listings loading -(with refresh opportunity).* -- caching readed directories *to localStorage (for now) -(so if network will disconnected or something heppen with a signal, we -definitely will can work cached copy of directory listings)*; -- key binding -- disabled js support *(working in limited mode)*. -- automated minification *client js-files and onstart-reading Cloud manager files on server starting.* - -**Cloud Commander** uses all benefits of js, so if js is disabled, -we moves to *limited mode*. - -Limited-mode features: ---------------- -- only 1 panel available -- no keybinding -- no local caching -- full loading of all web page(with styles, js-scripts, html-page etc). - -Hot keys: ---------------- -In all modern web browsers (but not in IE, becouse he special) hot keys works. -There is a short list: -- Ctrl + r - reload dir content -- Ctrl + d - clear local cache (wich contains dir contents) -- Alt + q - disable key bindings -- Alt + s - get all key bindings back -- up, down, enter - filesystem navigation - -Additional modules: ---------------- -**Cloud Commander** not using additional modules for main functionality. -But for minification and optimization tricks optional can be -assingned (and installed) modules: -- [UglifyJS] (https://github.com/mishoo/UglifyJS) -- [clean-css] (https://github.com/GoalSmashers/clean-css) -- [html-minifier] (https://github.com/kangax/html-minifier) -- [css-b64-images] (https://github.com/Filirom1/css-base64-images) - -Install addtitional modules: - - npm i uglify-js clean-css html-minifier css-b64-images \ No newline at end of file diff --git a/client.js b/client.js deleted file mode 100644 index c5c669c3..00000000 --- a/client.js +++ /dev/null @@ -1,713 +0,0 @@ -/* Функция которая возвратит обьект CloudCommander - * @window - обьект window - * @document - обьект document - * @CloudFunc - обьект содержащий общий функционал - * клиентский и серверный - */ - -var CloudCommander=(function(){ -"use strict"; - -/* Клиентский обьект, содержащий функциональную часть*/ -var CloudClient={ - /* Конструктор CloudClient, который - * выполняет весь функционал по - * инициализации - */ - init :function(){}, - - keyBinding :function(){},/* функция нажатий обработки клавишь */ - keyBinded :false,/* оброботка нажатий клавишь установлена*/ - _loadDir :function(){}, - /* - * Функция привязываеться ко всем ссылкам и - * загружает содержимое каталогов - */ - /* Обьект для работы с кэшем */ - Cashe :{}, - - /* ПРИВАТНЫЕ ФУНКЦИИ */ - /* функция загружает json-данные о файловой системе */ - _ajaxLoad :function(){}, - /* Функция генерирует JSON из html-таблицы файлов */ - _getJSONfromFileTable :function(){}, - /* функция меняет ссыки на ajax-овые */ - _changeLinks :function(){}, - /* ОБЬЕКТЫ */ - /* обьект, который содержит функции для отображения картинок*/ - _images :{}, - /* КОНСТАНТЫ*/ - /* название css-класа текущего файла*/ - CURRENT_FILE :'current-file', - LIBDIR :'/lib', - LIBDIRCLIENT :'/lib/client' -}; - -/* - * Обьект для работы с кэшем - * в него будут включены функции для - * работы с LocalStorage, webdb, - * idexed db etc. - */ -CloudClient.Cache={ - _allowed :true, /* приватный переключатель возможности работы с кэшем */ - /* функция проверяет возможно ли работать с кэшем каким-либо образом */ - isAllowed :function(){}, - /* Тип кэша, который доступен*/ - type :{}, - /* Функция устанавливает кэш, если выбранный вид поддерживаеться браузером*/ - set :function(){}, - /* Функция достаёт кэш, если выбранный вид поддерживаеться браузером*/ - get :function(){}, - /* функция чистит весь кэш для всех каталогов*/ - clear :function(){} -}; - -/* Обьект, который содержит - * функции для отображения - * картинок - */ -CloudClient._images={ - /* Функция создаёт картинку загрузки*/ - loading :function(){ - var e=document.createElement('span'); - e.className='icon loading'; - e.id='loading-image'; - return e; -}, - - /* Функция создаёт картинку ошибки загрузки*/ - error :function(){ - var e=document.createElement('span'); - e.className='icon error'; - e.id='error-image'; - return e; - } -}; - -/* функция проверяет поддерживаеться ли localStorage */ -CloudClient.Cache.isAllowed=(function(){ - if(window.localStorage && - localStorage.setItem && - localStorage.getItem){ - CloudClient.Cache._allowed=true; - }else - { - CloudClient.Cache._allowed=false; - /* загружаем PolyFill для localStorage, - * если он не поддерживаеться браузером - * https://gist.github.com/350433 - */ - /* - CloudClient.jsload('https://raw.github.com/gist/350433/c9d3834ace63e5f5d7c8e1f6e3e2874d477cb9c1/gistfile1.js', - function(){CloudClient.Cache._allowed=true; - }); - */ - } -}); - /* если доступен localStorage и - * в нём есть нужная нам директория - - * записываем данные в него - */ -CloudClient.Cache.set=(function(pName, pData){ - if(CloudClient.Cache._allowed && pName && pData){ - localStorage.setItem(pName,pData); - } -}); -/* Если доступен Cache принимаем из него данные*/ -CloudClient.Cache.get=(function(pName){ - if(CloudClient.Cache._allowed && pName){ - return localStorage.getItem(pName); - } - else return null; -}); -/* Функция очищает кэш*/ -CloudClient.Cache.clear=(function(){ - if(CloudClient.Cache._allowed){ - localStorage.clear(); - } -}); - - -/* функция обработки нажатий клавишь */ -CloudClient.keyBinding=(function(){ - /* loading keyBinding module and start it */ - CloudClient.jsload(CloudClient.LIBDIRCLIENT+'/keyBinding.js',function(){ - CloudCommander.keyBinding(); - }); -}); - - -/* - * Функция привязываеться ко всем ссылкам и - * загружает содержимое каталогов - */ -CloudClient._loadDir=(function(pLink,pNeedRefresh){ - /* @pElem - элемент, - * для которого нужно - * выполнить загрузку - */ - return function(){ - /* показываем гиф загрузки возле пути папки сверху*/ - LoadingImage.className='icon loading';/* показываем загрузку*/ - ErrorImage.className='icon error hidden';/* прячем ошибку */ - /* если элемент задан - - * работаем с ним - */ - /* если мы попали сюда с таблицы файлов*/ - try{ - this.firstChild.nextSibling.appendChild(LoadingImage); - }catch(error){ - /* если + - * кнопка обновления - */ - try{this.firstChild.parentElement.appendChild(LoadingImage);} - catch(error){console.log(error);} - } - - var lCurrentFile=document.getElementsByClassName(CloudClient.CURRENT_FILE); - /* получаем имя каталога в котором находимся*/ - var lHref; - try{ - lHref=lCurrentFile[0].parentElement.getElementsByClassName('path')[0].textContent; - }catch(error){console.log('error');} - - lHref=CloudFunc.removeLastSlash(lHref); - var lSubstr=lHref.substr(lHref,lHref.lastIndexOf('/')); - lHref=lHref.replace(lSubstr+'/',''); - - /* загружаем содержимое каталога*/ - CloudClient._ajaxLoad(pLink, pNeedRefresh); - - /* получаем все элементы выделенной папки*/ - /* при этом, если мы нажали обновить - * или +R - ссылок мы ненайдём - * и заходить не будем - */ - var lA=this.getElementsByTagName('a'); - /* если нажали на ссылку на верхний каталог*/ - if(lA.length>0 && lA[0].textContent==='..' && - lHref!=='/'){ - /* функция устанавливает курсор на каталог - * с которого мы пришли, если мы поднялись - * в верх по файловой структуре - */ - CloudClient._currentToParent(lHref); - } - - /* что бы не переходить по ссылкам - * а грузить всё ajax'ом, - * возвращаем false на событие - * onclick - */ - return false; - }; - }); - -/* Функция устанавливает текущим файлом, тот - * на который кликнули единожды - */ -CloudClient._setCurrent=(function(){ - /* - * @pFromEnter - если мы сюда попали - * из события нажатия на энтер - - * вызоветься _loadDir - */ - return function(pFromEnter){ - var lCurrentFile=document.getElementsByClassName(CloudClient.CURRENT_FILE); - if(lCurrentFile && lCurrentFile.length > 0){ - /* если мы находимся не на - * пути и не на заголовках - */ - if(this.className!=='path' && - this.className!=='fm_header'){ - - lCurrentFile[0].className=''; - /* устанавливаем курсор на файл, - * на который нажали */ - this.className=CloudClient.CURRENT_FILE; - } - } - /* если мы попали сюда с энтера*/ - if(pFromEnter===true){ - this.ondblclick(this); - }/* если мы попали сюда от клика мышки */ - else{pFromEnter.returnValue=false;} - - /* что бы не переходить по ссылкам - * а грузить всё ajax'ом, - * возвращаем false на событие - * onclick - */ - return false; - }; - }); - -/* функция устанавливает курсор на каталог - * с которого мы пришли, если мы поднялись - * в верх по файловой структуре - * @pDirName - имя каталога с которого мы пришли - */ -CloudClient._currentToParent = (function(pDirName){ - /* опредиляем в какой мы панели: - * правой или левой - */ - var lCurrentFile=document.getElementsByClassName(CloudClient.CURRENT_FILE); - var lPanel; - try{ - lPanel=lCurrentFile[0].parentElement.id; - }catch(error){console.log("Current file not found\n"+error);} - /* убираем слэш с имени каталога*/ - pDirName=pDirName.replace('/',''); - /* ищем файл с таким именем*/ - lPanel=document.getElementById(lPanel); - if(!lPanel)return; - - var lLi=lPanel.getElementsByTagName('li'); - for(var i=0;i0)lCurrentFile[0].className=''; - - lLi[i].className=CloudClient.CURRENT_FILE; - } - } -}); - -/* глобальные переменные */ -var LoadingImage; -var ErrorImage; - -var $; -var CloudFunc; -/* Конструктор CloudClient, который - * выполняет весь функционал по - * инициализации - */ -CloudClient.init=(function() -{ - /* меняем title - * если js включен - имена папок отображать необязательно... - * а может и обязательно при переходе, можно будет это сделать - */ - var lTitle=document.getElementsByTagName('title'); - if(lTitle.length>0)lTitle[0].textContent='Cloud Commander'; - - /* загружаем jquery: */ - CloudClient.jsload('//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js',function(){ - /* сохраняем переменную jQuery себе в область видимости */ - $=window.jQuery; - if(!window.jQuery)CloudClient.jsload('jquery.min.js', - function(){ - $=window.jQuery; - }); - }); - - /* загружаем общие функции для клиента и сервера*/ - CloudClient.jsload(CloudClient.LIBDIR+'/cloudfunc.js',function(){ - /* берём из обьекта window общий с сервером функционал */ - CloudFunc=window.CloudFunc; - - /* меняем ссылки на ajax'овые*/ - CloudClient._changeLinks(CloudFunc.LEFTPANEL); - CloudClient._changeLinks(CloudFunc.RIGHTPANEL); - - /* устанавливаем переменную доступности кэша*/ - CloudClient.Cache.isAllowed(); - /* Устанавливаем кэш корневого каталога */ - if(!CloudClient.Cache.get('/'))CloudClient.Cache.set('/',CloudClient._getJSONfromFileTable()); - } - ); - - LoadingImage=CloudClient._images.loading(); - /* загружаем иконку загрузки возле кнопки обновления дерева каталогов*/ - try{ - document.getElementsByClassName('path')[0].getElementsByTagName('a')[0].appendChild(LoadingImage); - LoadingImage.className+=' hidden'; /* прячем её */ - }catch(error){console.log(error);} - ErrorImage=CloudClient._images.error(); - - /* устанавливаем размер высоты таблицы файлов - * исходя из размеров разрешения экрана - */ - - /* формируем и округляем высоту экрана - * при разрешениии 1024x1280: - * 658 -> 700 - */ - - var lHeight=window.screen.height - (window.screen.height/3).toFixed(); - lHeight=(lHeight/100).toFixed()*100; - - var lFm=document.getElementById('fm'); - if(lFm)lFm.style.cssText='height:' + - lHeight + - 'px'; - - /* выделяем строку с первым файлом */ - var lFmHeader=document.getElementsByClassName('fm_header'); - if(lFmHeader && lFmHeader[0].nextSibling) - lFmHeader[0].nextSibling.className=CloudClient.CURRENT_FILE; - - /* показываем элементы, которые будут работать только, если есть js */ - var lFM=document.getElementById('fm'); - if(lFM)lFm.className='localstorage'; - - /* если есть js - показываем правую панель*/ - var lRight=document.getElementById('right'); - if(lRight)lRight.className=lRight.className.replace('hidden',''); - - CloudClient.cssSet({id:'show_2panels', - element:document.head, - inner:'#left{width:46%;}' - }); -}); - -/* функция меняет ссыки на ajax-овые */ -CloudClient._changeLinks = function(pPanelID) -{ - /* назначаем кнопку очистить кэш и показываем её*/ - var lClearcache=document.getElementById('clear-cache'); - if(lClearcache)lClearcache.onclick=CloudClient.Cache.clear; - - /* меняем ссылки на ajax-запросы */ - var lPanel=document.getElementById(pPanelID); - var a=lPanel.getElementsByTagName('a'); - - /* Если нажмут на кнопку перезагрузить страниц - её нужно будет обязательно - * перезагрузить - */ - /* номер ссылки очистки кэша*/ - //var lCLEARICON=0; - /* номер ссылки иконки обновления страницы */ - var lREFRESHICON=0; - - /* путь в ссылке, который говорит - * что js отключен - */ - var lNoJS_s = CloudFunc.NOJS; - var lFS_s = CloudFunc.FS; - - for(var i=0;i=3){ - element.onload=pFunc; - if(arguments.length>=4){ - element.style.cssText=pStyle; - } - } - //document.body - pElement.appendChild(element); - return element;//'elem '+src+' loaded'; - } - /* если js-файл уже загружен - * запускаем функцию onload - */ - else if(pFunc){ - try{ - pFunc(); - }catch(error){console.log(error);} - } -}; - -/* Функция загружает js-файл */ -CloudClient.jsload = function(pSrc,pFunc,pStyle,pId) -{ - CloudClient._anyload('script',pSrc,pFunc,pStyle,pId,document.body); -}; -/* Функция создаёт елемент style и записывает туда стили - * @pParams_o - структура параметров, заполняеться таким - * образом: {src: ' ',func: '', id: '', element: '', inner: ''} - * все параметры опциональны - */ -CloudClient.cssSet = function(pParams_o){ - var lElem=CloudClient._anyload('style', - pParams_o.src, - pParams_o.func, - pParams_o.style, - pParams_o.id, - pParams_o.element?pParams_o.element:document.body); - lElem.innerHTML=pParams_o.inner; -}; - -/* - * Функция генерирует JSON из html-таблицы файлов - */ -/* - * Используеться при первом заходе в корень - */ -CloudClient._getJSONfromFileTable=function() -{ - var lLeft=document.getElementById('left'); - var lPath=document.getElementsByClassName('path')[0].textContent; - var lFileTable=[{path:lPath,size:'dir'}]; - var lLI=lLeft.getElementsByTagName('li'); - - var j=1;/* счётчик реальных файлов */ - var i=1;/* счётчик элементов файлов в DOM */ - /* Если путь отличный от корневного - * второй элемент li - это ссылка на верхний - * каталог '..' - */ - i=2;/* пропускам Path и Header*/ - - - for(;ili{ - margin:10px; - } - /* если правая панель не помещаеться - прячем её */ - #right{ - display:none; - } - /* текущий файл под курсором */ - .current-file{ - background-color: rgba(49, 123, 249, .40); - color:white; - } - /* делаем иконки под курсом белыми*/ - .current-file > .mini-icon{ - color:white; - } - .current-file > .text-file::before{ - color:white; - } - -/* меняем иконки на шрифтовые*/ - .mini-icon { - font: 60px 'Octicons Regular'; - width: 40%; - height: 0; - margin-left: 0; - float: right; - position: relative; - top: -17px; - - color: rgba(246, 224, 124, 0.56); - } - .directory::before{ - content: '\f216'; - } - .text-file::before{ - color: rgba(26, 224, 124, 0.56); - content: '\f211'; - } - .text-file{ - background-image:none; - } - - /* убираем заголовок*/ - .fm_header{ - display:none; - } - .mode,.size,.owner{ - /* располагаем элементы - * один под другим - */ - display: table; - float: none; - width: 0; - - text-align: left; - } - /* выводим заголовки рядом с полями */ - .name::before{ - content: 'name:'; - font-weight: bold; - font-size: 13px; - } - .mode::before{ - content: 'mode:'; - font-weight: bold; - font-size: 13px; - } - .size::before{ - content: 'size:'; - font-weight: bold; - font-size: 13px; - } - .owner::before{ - content: 'owner:'; - font-weight: bold; - font-size: 13px; - } - - .name{ - float: none; - width:100%; - font-size: 18px; - } -} -@media only screen and (min-width: 601px) and (max-width: 785px){ - #left{ - width:90% !important; - } - #right{ - display:none; - } -} - -@media only screen and (min-width:786px) and (max-width: 1155px){ - #left{ - width:90% !important; - } - /* если правая панель не помещаеться - прячем её */ - #right{ - display:none; - } -} \ No newline at end of file diff --git a/img/console_clear.png b/img/console_clear.png deleted file mode 100644 index f5739eb13b9c313415b984ea96ad47505c9dd7e7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1344 zcmV-G1;6@1^@s6nD_O6000FCNkl-&xG_lrq5JXm++URcxOi=C%>~R;c#Bt8S0&&E5Hja3i;IivGcz-!xw-j(mw07mC2V0~ z;XtF&kmcp&X`H*^e0_3qlBm^n#Mjqvm9rQk$K>SX*p`+S-N?uYnV6U$80qo&_&BMp zttAqP^fB7Ga1t*qEzyzgK=6S~7W7+VVo$x&rxRZ3u> zOfScE{m9YoW0S?0$3N@qAL;O@dpS8dq`SMD^z`)5`8}$rs7MJ22;8Le+tk!Vu3vvI z!(?$5Q{(>hy!xq2Yfi<$MlV3 zT(1d)LSa0e6z&A(cxnx<{$qoV*c^ZBIXzWY+~N=&nD&_|7>F3@y{ma9sg`% zp7GBv<{ba5Vh0BYDz-33{2R73oW26NTrQ=B!yNH%C_rJHCaU_N5N$qE32|%B{f#-~q%u@n9U*FL(UAf;`X*zUN6V z<8U>IJwOj=0A-*E6mq19>D$1#!~$z;>#y)d1+u|sKmpP?qM&^lM>(AL1(ueURrCUj zkjo9S;H(zlCHRhtkKcY4a$k%l#EkQ#5UTfsHptZ)KoQUfYM01MdQDrp+WnM zQ5ORId5$zbKE8NvZcdBHqA~T0L?Zbb<#fvs|CcU#Z=USKDt2~u&OpRJG>-rI`FWio z{(XFWwry-|vN(z3;^K;t)K8L! z1qDAfj(;RHYWJhlfWT z+1Z`>#$@sN^R82wnVC~+wR+#%+j~1dKYzeZ^;+}vH<;Abqg4LpGk(!VfLrag-ol_>97 zTiVgl@qtM6>Z($y98{?)v>c=gIKLH$M54RTD?(0A&fOO;zP@dul%mu-QCuY0K^f*M zn{cI5r#}9%ZhhU|-9NImwN2$)=xJZ-psrJm|9=3w$r4qVmLG}$0000x(K@^6+>g^d@v4;gkbWsEoXE%32*i1tcpTNXd5CcIl)ECgqz|2rE6EW}s7R?kl za1q`0GCkMruC6-2LANtwVlsgzsp4?{@7$`KBv!G66>Vie3h?3OmEEkjwdLG0PgLVi z`!N((f$A@n17Ldj#`};0I3@iHJ5M{#IZz|UIYRm4(!uV7eYIYIwQf&}_2J~}>pQ^n z6o8--^T(=hkBNQ_k{-_GWE;FMW7!p}f{NG3nHZ{D5<3d8&tLh%a4AqqnjMkr3m&fkMdECD3N5}Unig5wy40;>lo4j~k+e}v)` zR6)J8Mk*u=SpB`p6o)7j?S0T@9?bz#m@l>gc*zk__|*!FMcHwP!gwLJvS~9c0px8E zW-!=9%H93I*%*Z8=x$dA&dD~$D#ws+K{GQN()gz!9L&jK+m?%ta#Ng#%LpbBNoY3B#?};^W4ea|M9+}o zHdC0d@8fOgzx&s(hgNN>reIf=V)iIwe@=tlS^Z^U*t?c$nwvM@PHQ5tkP zH-)B-Mq`7fP!!Eyd~nL83rQ4)|3~a@{N+69jegYHY3LuZxR?j&Rg( zPR07x9`1ZD#|O8G-ntj8_HQXyY9i(tVWd9NjbO4rIv&%;esZ6qJG=idk${yrEWlMrvxH7xey@*#~8ywwu|0 z)svn+awvo8ooru?o>KJ^1|_LLspI?9dj{jttL3#^3xM*lrKE|^FL5>V|Z6PM$qllk=|_^ZK-V(${mTKO4ZY-M}wa6qM=bJ@09jxyC2Hc zBF@xIj+>6SwwiwW(&F$#Y3Sl-!9sR+nMfeV>u)|N(^D%|{T_ab#w7d}0-RCWfL>r2Y@ZJK_=UpZo#K^zc-BA}1#R0000g($p8XB6Knwp!NTUuILTU)PQz1r5+*52N3GMT!%x_Wwg zdV6~Z1_lNP2Zx4+hKGkoMn*dAeCMNFOxidLAIW;vkJv}`$GxOlVgU62_ zKY8-x>C>lkb8`y|3yX`3OG``3%gZY(E32!kYiny}v-#!Am+R~6ymi9X@OZ5|=$3Ac*%IgT+Ds5+OGdk_-B4F{dAcdAsVTz+%sNqp=LM4kzb?{0I z;Bz=G_C%7MC{enBL1!z)8|7O>CCWe^*>Uq0Hiat%awm$Q!Y#nx%ULG0cP#MSC7}pi znBEk3;4eG{f*4FWj|O%l84+(L?P{oSw#38uvnG)ZZ+hDkFoWN&DomB1{ zjl0?f$RtSX%!3ZVRRQYWApJ;=oN@V{ch5`Pp%I(?a3*b!(AJ-(x=?je>q56RP z`&&@0ahx7+72}@1-1+BKffxy;hb*QAAxO|FHP9nNxoauxL_2-NktKHRL3+tnwy?RjN$+Zicb zGBLx;8e@gaVDK}69D|}nX@oXnI|!S}2JYnGOe3(s;UE-Jn;n9SGu=fL!)KMH3elT) zq@5g&on39$(Z3#Ol<^%)PSXVo@E&q6`cSTrjO&%y`>vBZRF7tVaM(pbqh&-VhzUFx zAqs1hWVaY)*e%^*0kMXxkk*L*^>%P&;+jFh5-IyB8C89Gd22-x+jxV%#Di|LEwkjyu(vg~l-y8JRso0YmVQ5EkVH9_bWdmriPn;Xz0HU?r-}Ym*JU~Gu z#H!z-Sig~NtEtil^EbXk5q|z4muDm>JIP0rwG7WD3S+9GBJ~;heG|L%tnJOt3;ODZ z-=AxhB~Tm|@--{&wt!9Dq!z~jdjgQsj;d1ui)`r{g#3l@`Y+o|m4+ohb8%lK3Tosj z`cr?TkjIV;SJxUp<&q1u2@0f zfjG4{K?pdGK(syql%&93%2zra#Xu0BrOCKFA;`ks$&+C#5QQ<|d}62BjvZR2H60wE-&H;pyTSqH(@-Vl>|&1p(LP>kg~E zYiz5X^`c$+%8#zC{u)yfe-5 zmgid={Z3k(ERKCKrE7DF;=x4^O+ pzO8rLO8p|Ip=x)jHOtWj`bJBmKdh_V<`47(gQu&X%Q~loCIFbEay|e6 diff --git a/index.html b/index.html deleted file mode 100644 index 6524a912..00000000 --- a/index.html +++ /dev/null @@ -1,54 +0,0 @@ - - - - - - - Cloud Commander - - - - - - - - - - -
    -
    - - - - \ No newline at end of file diff --git a/lib/README.md b/lib/README.md deleted file mode 100644 index a741f80c..00000000 --- a/lib/README.md +++ /dev/null @@ -1,5 +0,0 @@ -Cloud Commander Libraries -=============== -**Cloud Commander Libraries** - dir thet contains scripts, thet uses -on client and server side, and modules, wich is not necessary -for CloudCommander work, but they adds some sugor. \ No newline at end of file diff --git a/lib/client/keyBinding.js b/lib/client/keyBinding.js deleted file mode 100644 index a441671f..00000000 --- a/lib/client/keyBinding.js +++ /dev/null @@ -1,248 +0,0 @@ -var CloudCommander; -var CloudFunc; -CloudCommander.keyBinding=(function(){ - "use strict"; - var key_event=function(event){ - /* - * Делаем допущение что перезагружать Cloud Commander - * посетителям не придёться, в любом случае, параметр - * должен быть опциональным и должна быть возможность - * его отключить. В любом случае, кроме хакеров и - * разработчиков (при чём сомнительно, что хакерам - * это пригодиться), функция перезагрузки никому не - * нужна, поскольку загружать весь дополнительный - * контент снова (js,css) в готовой версии нет - * необходимости. - * - */ - //console.log(event.keyCode); - var lCurrentFile; - var lName; - /* если клавиши можно обрабатывать*/ - if(CloudCommander.keyBinded){ - /* если нажали таб: - * переносим курсор на - * правую панель, если - * мы были на левой и - * наоборот - */ - if(event.keyCode===9){ - console.log('Tab pressed'); - try{ - lCurrentFile=document.getElementsByClassName(CloudCommander.CURRENT_FILE)[0]; - }catch(error){console.log(error);} - } - /* навигация по таблице файлов*/ - /* если нажали клавишу вверх*/ - else if(event.keyCode===38){ - /* получаем выдленный файл*/ - lCurrentFile=document.getElementsByClassName(CloudCommander.CURRENT_FILE); - /* если ненайдены выделенные файлы - выходим*/ - if(lCurrentFile.length===0)return; - lCurrentFile=lCurrentFile[0]; - /* если это строка существет и - * если она не заголовок - * файловой таблицы - */ - if(lCurrentFile.previousSibling && - lCurrentFile.previousSibling.className!=='fm_header' ){ - /* убираем выделение с текущего элемента */ - lCurrentFile.className=''; - /* и выделяем предыдущую строку*/ - lCurrentFile.previousSibling.className=CloudCommander.CURRENT_FILE; - event.preventDefault(); - } - } - /* если нажали клавишу в низ*/ - else if(event.keyCode===40){ - /* получаем выдленный файл*/ - lCurrentFile=document.getElementsByClassName(CloudCommander.CURRENT_FILE); - /* если ненайдены выделенные файлы - выходим*/ - if(lCurrentFile.length===0)return; - lCurrentFile=lCurrentFile[0]; - /* если это не последняя строка */ - if(lCurrentFile.nextSibling){ - /* убираем с него выделение */ - lCurrentFile.className=''; - /* выделяем следующую строку*/ - lCurrentFile.nextSibling.className=CloudCommander.CURRENT_FILE; - event.preventDefault(); - } - } - /* если нажали клавишу page up или Home - * переходим к самому верхнему - * элементу - */ - else if(/*event.keyCode===33 ||*/ event.keyCode===36){ - lCurrentFile=document.getElementsByClassName(CloudCommander.CURRENT_FILE)[0]; - /* убираем выделение с текущего файла*/ - lCurrentFile.className=''; - /* получаем первый элемент*/ - lCurrentFile.parentElement.firstElementChild - /* пропускаем путь и заголовки столбиков*/ - .nextElementSibling.nextElementSibling - /* выделяем верхий файл */ - .className=CloudCommander.CURRENT_FILE; - } - /* если нажали клавишу page down или End - * выделяем последний элемент - */ - else if(/*event.keyCode===34 ||*/ event.keyCode===35){ - lCurrentFile=document.getElementsByClassName(CloudCommander.CURRENT_FILE)[0]; - /* снимаем выделение с текущего файла*/ - lCurrentFile.className=''; - /* выделяем самый нижний файл */ - lCurrentFile.parentElement.lastElementChild.className=CloudCommander.CURRENT_FILE; - } - /* если нажали Enter - открываем папку*/ - else if(event.keyCode===13){ - lCurrentFile=document.getElementsByClassName(CloudCommander.CURRENT_FILE); - /* если ненайдены выделенные файлы - выходим*/ - if(!lCurrentFile.length)return; - lCurrentFile=lCurrentFile[0]; - /* из него достаём спан с именем файла*/ - lName=lCurrentFile.getElementsByClassName('name'); - /* если нету (что вряд ли) - выходим*/ - if(!lName)return false; - /* достаём все ссылки*/ - var lATag=lName[0].getElementsByTagName('a'); - /* если нету - выходим */ - if(!lATag)return false; - /* получаем ссылку на каталог, - * что на уровень выше - */ - /* получаем имя каталога в котором находимся*/ - var lHref; - try{ - lHref=lCurrentFile.parentElement.getElementsByClassName('path')[0].textContent; - }catch(error){console.log('error');} - lHref=CloudFunc.removeLastSlash(lHref); - var lSubstr=lHref.substr(lHref,lHref.lastIndexOf('/')); - lHref=lHref.replace(lSubstr+'/',''); - - /* вызываем ajaxload привязанный через changelinks - * пробулем нажать на ссылку, если не получиться - * (opera, ie), вызываем событие onclick, - * которое пока не прописано у файлов - */ - - if(lCurrentFile.onclick)lCurrentFile.onclick(true); - else try{ - lATag[0].click(); - } - catch(error){ - console.log(error); - } - } - /* если нажали +r */ - else if(event.keyCode===82 && - event.ctrlKey){ - console.log('+r pressed'); - console.log('reloading page...'); - console.log('press +q to remove all key-handlers'); - - /* обновляем страницу, */ - /* Загружаем содержимое каталога - * при этом данные берём всегда из - * сервера, а не из кэша - * (обновляем кэш) - */ - /* Программно нажимаем на кнопку перезагрузки - * содержимого каталога - */ - var lRefreshIcon=document.getElementsByClassName(CloudFunc.REFRESHICON); - if(lRefreshIcon)lRefreshIcon=lRefreshIcon[0]; - if(lRefreshIcon){ - /* находим файл который сейчас выделен */ - lCurrentFile=document.getElementsByClassName(CloudCommander.CURRENT_FILE); - if(lCurrentFile.length>0)lCurrentFile=lCurrentFile[0]; - /* получаем название файла*/ - var lSelectedName=lCurrentFile.getElementsByTagName('a')[0].textContent; - /* если нашли элемент нажимаем него - * а если не можем - нажимаем на - * ссылку, на которую повешен eventHandler - * onclick - */ - if(lRefreshIcon.click)lRefreshIcon.parentElement.click(); - else lRefreshIcon.parentElement.onclick(); - - /* перебираем файлы левой панели - * в поисках подсвеченого файла - */ - var lLeft=document.getElementById('left'); - if(lLeft){ - /* перебираем все файлы в панели */ - var lLi=lLeft.getElementsByTagName('li'); - lCurrentFile.className=''; - /* начинаем с 2-ух, по скольку - * 0 - это путь - * 1 - это заголовок файловой таблицы - */ - for(var i=2;i+d чистим кэш */ - else if(event.keyCode===68 && - event.ctrlKey){ - console.log('+d pressed'); - console.log('clearing cache...'); - console.log('press +q to remove all key-handlers'); - - var lClearCache=document.getElementById('clear-cache'); - if(lClearCache && lClearCache.onclick)lClearCache.onclick(); - - event.preventDefault();//запрет на дальнейшее действие - } - /* если нажали +q - * убираем все обработчики - * нажатий клавиш - */ - else if(event.keyCode===81 && - event.altKey){ - //document.removeEventListener('keydown', key_event,false); - console.log('+q pressed'); - console.log('+r reload key-handerl - removed'); - console.log('+s clear cache key-handler - removed'); - console.log('press +s to to set them'); - - /* обработчик нажатий клавиш снят*/ - CloudCommander.keyBinded=false; - } - } - /* если нажали +s - * устанавливаем все обработчики - * нажатий клавиш - */ - else if(event.keyCode===83 && - event.altKey){ - /* - document.addEventListener('keydown', key_event,false); - */ - /* обрабатываем нажатия на клавиши*/ - CloudCommander.keyBinded=true; - - console.log('+s pressed'); - console.log('+r reload key-handerl - set'); - console.log('+s clear cache key-handler - set'); - console.log('press +q to remove them'); - } - - return false; - }; - /* добавляем обработчик клавишь */ - if(document.addEventListener) - document.addEventListener('keydown', key_event,false); - else document.onkeypress=key_event; - /* клавиши назначены*/ - CloudCommander.keyBinded=true; -}); \ No newline at end of file diff --git a/lib/cloudfunc.js b/lib/cloudfunc.js deleted file mode 100644 index 231f36dd..00000000 --- a/lib/cloudfunc.js +++ /dev/null @@ -1,504 +0,0 @@ -"use strict"; -/* Модуль, содержащий функции, которые будут работать - * и на клиенте и на сервере - * - * Правила названий: - * varName - имя функции - * lVarName - имя локальной переменной - * pVarName - имя параметра - * fVarName - имя функции созданной внутри функции - * VARNAME - имя константы - * - * Типы переменных: - * varNameS - строка - * varNameN - число - * varNameO - обьект - * varNameM - массив - */ - -var CloudFunc={ - /* Путь с которым мы сейчас работаем */ - Path :'', - /* КОНСТАНТЫ (общие для клиента и сервера)*/ - /* название программы */ - NAME :'Cloud Commander', - /* если в ссылке будет эта строка - - * в браузере js отключен - */ - NOJS : '/no-js', - FS : '/c/f/s', - /* название css-класа кнопки обновления файловой структуры*/ - REFRESHICON : 'refresh-icon', - /* id панелей с файлами */ - LEFTPANEL : 'left', - RIGHTPANEL : 'right' - /* name of direcotory with libs */ -}; - -/* - * Функция убирает последний слеш, - * если он - последний символ строки - */ -CloudFunc.removeLastSlash = function(pPath){ - if(typeof pPath==='string') - return (pPath.lastIndexOf('/')===pPath.length-1)? - pPath.substr(pPath, pPath.length-1):pPath; - else return pPath; -}; -/* - * Функция меняет код символа пробела на пробел - * в переданной строке - * @pPath - строка - */ -CloudFunc.replaceSpaces = function(pPath){ - if(pPath.indexOf('%20')>0){ - do{ - pPath=pPath.replace('%20',' '); - }while(pPath.indexOf('%20')>0); - } - return pPath; -}; - -/* Функция возвращает заголовок веб страницы */ -CloudFunc.setTitle = function(){ - - return CloudFunc.Path===''?CloudFunc.NAME: - CloudFunc.Path + - ' - ' + - CloudFunc.NAME; -}; -/* Функция переводит права из цыфрового вида в символьный - * @pPerm_s - строка с правами доступа - * к файлу в 8-миричной системе - */ -CloudFunc.convertPermissionsToSymbolic= function(pPerm_s){ - /* - S_IRUSR 0000400 protection: readable by owner - S_IWUSR 0000200 writable by owner - S_IXUSR 0000100 executable by owner - S_IRGRP 0000040 readable by group - S_IWGRP 0000020 writable by group - S_IXGRP 0000010 executable by group - S_IROTH 0000004 readable by all - S_IWOTH 0000002 writable by all - S_IXOTH 0000001 executable by all - */ - if(pPerm_s===undefined) return; - - /* тип файла */ - var lType=pPerm_s.charAt(0); - - switch (lType-0) { - case 1: /* обычный файл */ - lType='-'; - break; - case 2: /* байт-ориентированное (символьное) устройство*/ - lType='c'; - break; - case 4: /* каталог */ - lType='d'; - break; - default: - lType='-'; - } - - /* оставляем последние 3 символа*/ - pPerm_s=pPerm_s.length>5?pPerm_s.substr(3):pPerm_s.substr(2); - - /* Рекомендации гугла советуют вместо string[3] - * использовать string.charAt(3) - */ -/* - http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml?showone=Standards_features#Standards_features - - Always preferred over non-standards featuresFor - maximum portability and compatibility, always - prefer standards features over non-standards - features (e.g., string.charAt(3) over string[3] - and element access with DOM functions instead - of using an application-specific shorthand). -*/ - /* Переводим в двоичную систему */ - var lOwner=(pPerm_s[0]-0).toString(2); - var lGroup=(pPerm_s[1]-0).toString(2); - var lAll =(pPerm_s[2]-0).toString(2); - /* - console.log(lOwner+' '+lGroup+' '+lAll); - */ - /* переводим в символьную систему*/ - var lPermissions=//lType+' '+ - (lOwner[0]-0>0?'r':'-')+ - (lOwner[1]-0>0?'w':'-')+ - (lOwner[2]-0>0?'x':'-')+ - ' ' + - (lGroup[0]-0>0?'r':'-')+ - (lGroup[1]-0>0?'w':'-')+ - (lGroup[2]-0>0?'x':'-')+ - ' ' + - (lAll[0]-0>0?'r':'-')+ - (lAll[1]-0>0?'w':'-')+ - (lAll[2]-0>0?'x':'-'); - /* - console.log(lPermissions); - */ - return lPermissions; -}; - -/* Функция конвертирует права доступа к файлам из символьного вида - * в цыфровой - */ -CloudFunc.convertPermissionsToNumberic= function(pPerm_s){ - /* если передана правильная строка, конвертированная - * функциец convertPermissionsToSymbolic - */ - if(!pPerm_s || pPerm_s.length!==11)return pPerm_s; - - var lOwner= (pPerm_s[0]==='r'?4:0) + - (pPerm_s[1]==='w'?2:0) + - (pPerm_s[2]==='x'?1:0); - var lGroup= (pPerm_s[4]==='r'?4:0) + - (pPerm_s[5]==='w'?2:0) + - (pPerm_s[6]==='x'?1:0); - var lAll = (pPerm_s[8]==='r'?4:0) + - (pPerm_s[9]==='w'?2:0) + - (pPerm_s[10]==='x'?1:0); - /* добавляем 2 цыфры до 5 */ - return '00'+lOwner+lGroup+lAll; -}; -/* Функция получает короткие размеры - * конвертируя байт в килобайты, мегабойты, - * гигайбайты и терабайты - * @pSize - размер в байтах - */ -CloudFunc.getShortedSize=function(pSize){ - /* if pSize=0 - return it */ - if(!pSize)return pSize; - - /* Константы размеров, что используются - * внутри функции - */ - var l1BMAX=1024; - var l1KBMAX=1048576; - var l1MBMAX=1073741824; - var l1GBMAX=1099511627776; - var l1TBMAX=1125899906842624; - - var lShorted; - - if(pSize2){ - if(folders[0].lastIndexOf('/')===folders[0].length) - LPrevDir=folders[1]; - else LPrevDir=folders[2]; - }else LPrevDir='/'; - */ - /* ################################### */ - - /* Формируем ссылки на каждый каталог в пути */ - var lHref=''; - var lHrefEnd=''; - - var lHtmlPath; - /* путь в ссылке, который говорит - * что js отключен - */ - var lNoJS_s=CloudFunc.NOJS; - var lFS_s=CloudFunc.FS; - /* корневой каталог */ - lHtmlPath=lHref+lFS_s+lNoJS_s+lTitle+'"/"'+_l+'/'+lHrefEnd; - for(i=folders.length-1;i>0;i--) - { - var lUrl=folders[i]; - var lShortName=lUrl.replace(lUrl.substr(lUrl,lUrl.lastIndexOf('/')+1),''); - if(i!==1) - { - lHtmlPath+=lHref+lFS_s+lNoJS_s+lUrl+lTitle+lUrl+_l+lShortName+lHrefEnd+'/'; - } - else - lHtmlPath+=lShortName+'/'; - } - /* *** */ - return lHtmlPath; -}; - -/* - * Функция ищет в имени файла расширение - * и если находит возвращает true - * @pName - получает имя файла - * @pExt - расширение - */ -CloudFunc.checkExtension=function(pName,pExt) -{ - /* если длина имени больше - * длинны расширения - - * имеет смысл продолжать - */ - if(pName.length>pExt.length){ - var lLength=pName.length; /* длина имени*/ - var lExtNum=pName.lastIndexOf(pExt);/* последнее вхождение расширения*/ - var lExtSub=lLength-lExtNum; /* длина расширения*/ - /* если pExt - расширение pName */ - if(lExtSub===pExt.length) - return true; - else - return false; - } - else return false; -}; - -/* - * Функция формирует заголовки столбиков - * @pFileTableTitles - массив названий столбиков - */ -CloudFunc._getFileTableHeader=function(pFileTableTitles) -{ - var lHeader='
  • '; - lHeader+=''; - for(var i=0;i'+ - lStr+ - ''; - } - lHeader+='
  • '; - - return lHeader; -}; - -/* - * Функция строит таблицу файлв из JSON-информации о файлах - * @pJSON - информация о файлах - * @pKeyBinded - если клавиши назначены, выделяем верхний файл - * [{path:'путь',size:'dir'}, - * {name:'имя',size:'размер',mode:'права доступа'}] - */ -CloudFunc.buildFromJSON=function(pJSON,pKeyBinded) -{ - var files; - /* - * если пропарсить стандартными - * функциями нельзя - - * пробуем eval, - */ - /* - * Если мы на клиенте и нет JSON - - * через eval парсим. - * Если-же мы на сервере, - * или на клиенте всё есть - * парсим стандарным методом - */ - - /* По скольку мы прописали заголовок application/json - * нет необходимости его конвертировать, - * но она есть, если мы вытягиваем данные из - * localStorage - */ - files=pJSON; - /* сохраняем путь каталога в котором мы сейчас находимся*/ - var lPath=files[0].path; - - /* сохраняем путь */ - CloudFunc.Path=lPath; - - /* - * Строим путь каталога в котором мы находимся - * со всеми подкаталогами - */ - var lHtmlPath=CloudFunc._getDirPath(lPath); - - /* Убираем последний слэш - * с пути для кнопки обновить страницу - * если он есть - */ - var lRefreshPath=CloudFunc.removeLastSlash(lPath); - - /* путь в ссылке, который говорит - * что js отключен - */ - var lNoJS_s=CloudFunc.NOJS; - var lFS_s=CloudFunc.FS; - - var lFileTable='
  • '+ - ''+ - ''+ - '' + - ''+ - ''+ - ''+lHtmlPath+''+ - '
  • '; - - var fileTableTitles=['name','size','owner','mode']; - lFileTable+=CloudFunc._getFileTableHeader(fileTableTitles); - /* Если мы не в корне */ - if(lPath!=='/'){ - /* ссылка на верхний каталог*/ - var lDotDot; - /* убираем последний слеш и каталог в котором мы сейчас находимся*/ - lDotDot=lPath.substr(lPath,lPath.lastIndexOf('/')); - lDotDot=lDotDot.substr(lDotDot,lDotDot.lastIndexOf('/')); - /* Если предыдущий каталог корневой */ - if(lDotDot==='')lDotDot='/'; - - /* Сохраняем путь к каталогу верхнего уровня*/ - lFileTable += '
  • '+ - '' + - '' + - '' + - ''+".." + - '' + - '<dir>'+ - '.' + - '' + - '
  • '; - } - var lLength=files.length; - - for(var i=1;i'; - lFileTable +=''; - lFileTable +='' + - '16? - ' title="'+files[i].name+'">' + - files[i].name.substr( - files[i].name,16)+ - '..':'>'+files[i].name) + - "" + - ''; - /* если папка - не выводим размер */ - lFileTable +='' + - (files[i].size==='dir'? - '<dir>': - /* если это файл - получаем - * короткий размер - */ - CloudFunc.getShortedSize( - files[i].size)); - lFileTable +='' + - '' + - (!files[i].uid?'root':files[i].uid) + - '' + - '' + - /* конвертируем названия разрешений - * из числового формата в буквенный - * при этом корневой каталог не трогаем - * по скольку в нём и так всё уже - * установлено еще на сервере - */ - (//lPath==='/'?files[i].mode: - CloudFunc.convertPermissionsToSymbolic(files[i].mode)) + - ''; - lFileTable +=''; - } - - /* если клавиши назначены и - * мы в корневом каталоге и - * верхний файл еще не выделен - - * выделяем верхний файл - */ - if(pKeyBinded && lPath==='/'&& - lFileTable.indexOf('
  • ')<0){ - lFileTable=lFileTable.replace('
  • ','
  • '); - } - - - - return lFileTable; -}; - -/* - * Если мы на стороне сервера - - * прописываем экспортируемые функции - */ -try{ - if(exports){ - /* экспортируемые функции */ - exports.checkExtension = CloudFunc.checkExtension; - exports.buildFromJSON = CloudFunc.buildFromJSON; - exports.replaceSpaces = CloudFunc.replaceSpaces; - exports.setTitle = CloudFunc.setTitle; - exports.convertPermissions = CloudFunc.convertPermissions; - exports.getUserUIDsAndNames = CloudFunc.getUserUIDsAndNames; - - /* константы*/ - exports.Name = CloudFunc.NAME; - exports.NOJS = CloudFunc.NOJS; - exports.FS =CloudFunc.FS; - - console.log('cloudfunc.js loaded...'); - } -}catch(err){ - /* если мы на клиенте */ -} \ No newline at end of file diff --git a/lib/server/minify.js b/lib/server/minify.js deleted file mode 100644 index 86571283..00000000 --- a/lib/server/minify.js +++ /dev/null @@ -1,279 +0,0 @@ -/* Модуль сжатия js-скриптов и css*/ - -/* функция сжимает js-скрипты - * и сохраняет их с именем .min.js - */ - -var fs = require('fs'); - -/* CONSTANTS */ -/* dir contains css-files */ -var CSSDIR = 'css/'; - -exports.jsScripts=function jsScripts(){ - 'use strict'; - - /* подключаем модуль uglify-js - * если его нет - дальнейшая - * работа функции не имеет смысла - */ - try{ - var jsp = require("uglify-js").parser; - var pro = require("uglify-js").uglify; - }catch(error){ - console.log('can\'n load uglify-js\n' + - 'to use js-minification you need to install uglify-js\n' + - 'npm install uglify-js\n' + - 'https://github.com/mishoo/UglifyJS'); - return false; - } - /* Константы */ - var CLIENT_JS='client.js'; - var CLOUDFUNC_JS='lib/cloudfunc.js'; - var CLIENT_KEYBINDING_JS='lib/client/keyBinding.js'; - - var dataReaded_f=function(pFileName, pData){ - console.log('file ' + pFileName + ' readed'); - - /*********************************/ - /* сжимаем код через uglify-js */ - var uglify_js=function(pDdata){ - var orig_code = pDdata.toString(); - var ast = jsp.parse(orig_code); // parse code and get the initial AST - ast = pro.ast_mangle(ast); // get a new AST with mangled names - ast = pro.ast_squeeze(ast); // get an AST with compression optimizations - var result_code = pro.gen_code(ast); // compressed code here - return result_code; - }; - /*********************************/ - var final_code=uglify_js(pData); - - var minFileName=pFileName.replace('.js','.min.js'); - /* если мы сжимаем client.js - - * меняем строку cloudfunc.js на - * cloudfunc.min.js и выводим сообщение - * - * меняем строку keyBinding.js на - * keyBinding.min.js - * если другой файл - ничего не деалем - */ - if(pFileName===CLIENT_JS) - console.log('file name of ' + - CLOUDFUNC_JS + - ' in ' + - CLIENT_JS + - ' changed. size:', - (final_code=final_code - .replace('cloudfunc.js','cloudfunc.min.js') - .replace('keyBinding.js','keyBinding.min.js')).length); - - /* записываем сжатый js-скрипт*/ - fs.writeFile(minFileName, final_code, fileWrited(minFileName)); - }; - console.log('reading file ' + CLIENT_JS+'...'); - fs.readFile(CLIENT_JS,fileReaded(CLIENT_JS,dataReaded_f)); - - console.log('reading file ' + CLOUDFUNC_JS+'...'); - fs.readFile(CLOUDFUNC_JS,fileReaded(CLOUDFUNC_JS,dataReaded_f)); - - console.log('reading file ' + CLIENT_KEYBINDING_JS+'...'); - fs.readFile(CLIENT_KEYBINDING_JS, fileReaded(CLIENT_KEYBINDING_JS,dataReaded_f)); - - - return true; -}; - -/* функция сжимает css-стили - * и сохраняет их с именем .min.css - * @pImgConvertToBase64_b - булевый признак, - * который отвечает за то, что быконвертировать - * картинки в base64 и поместить в выходной css файл - */ -exports.cssStyles=function cssStyles(pImgConvertToBase64_b){ - 'use strict'; - - /* connecting cleanCSS, - * if we can't find it - - * return false - */ - var cleanCSS; - try{ - cleanCSS = require('clean-css'); - }catch(error){ - console.log('can\'n load clean-css \n' + - 'to use css-minification you need to install clean-css \n' + - 'npm install clean-css\n' + - 'https://github.com/GoalSmashers/clean-css'); - return false; - } - - /* Константы */ - var STYLE_CSS = CSSDIR+'style.css'; - var RESET_CSS = CSSDIR+'reset.css'; - - var lAllStyle=''; - var lResetCssDone=false; - var lStyleCssDone=false; - var dataReaded_f=function(pFileName, pData){ - console.log('file ' + pFileName + ' readed'); - /*********************************/ - /* сжимаем код через clean-css */ - var clean_css=function(pData){ - /* Сохраняем весь стиль в одну переменную*/ - return cleanCSS.process(pData); - }; - /*********************************/ - var final_code=clean_css(pData); - - lAllStyle+=final_code; - - var minFileName=pFileName.replace('.css','.min.css'); - - if(pFileName===STYLE_CSS)lStyleCssDone=true; - if(pFileName===RESET_CSS)lResetCssDone=true; - /* if all files writed we - * save all minimized css - * to one file all.min.css - */ - if(lStyleCssDone && lResetCssDone){ - /* если включена конвертация картинок в base64 - * вызываем её - */ - if(pImgConvertToBase64_b) - base64_images(lAllStyle); - else - fs.writeFile(CSSDIR+'all.min.css', lAllStyle, fileWrited('all.min.css')); - } - /* в другом случае - записываем сжатый css файл*/ - else fs.writeFile(minFileName, final_code, fileWrited(minFileName)); - }; - - console.log('reading file ' + STYLE_CSS+'...'); - fs.readFile(STYLE_CSS,fileReaded(STYLE_CSS,dataReaded_f)); - - console.log('reading file ' + RESET_CSS+'...'); - fs.readFile(RESET_CSS,fileReaded(RESET_CSS,dataReaded_f)); - - return true; -}; - -/* функция сжимает css-стили - * и сохраняет их с именем .min.css - */ -exports.html=function(){ - 'use strict'; - - /* connecting cleanCSS, - * if we can't find it - - * return false - */ - var htmlMinifier; - try{ - htmlMinifier = require('html-minifier'); - }catch(error){ - console.log('can\'n load html-minifier \n' + - 'to use html-minification you need to install html-minifier\n' + - 'npm install html-minifier\n' + - 'https://github.com/kangax/html-minifier'); - return false; - } - - /* Константы */ - var INDEX_HTML='index.html'; - - var dataReaded_f=function(pFileName, pData){ - console.log('file ' + pFileName + ' readed'); - /*********************************/ - /* сжимаем код через clean-css */ - var html_minify=function(pData){ - /* Сохраняем весь стиль в одну переменную*/ - - var lOptions={ - removeComments: true, - removeCommentsFromCDATA: true, - removeCDATASectionsFromCDATA: true, - collapseWhitespace: true, - collapseBooleanAttributes: true, - removeAttributeQuotes: true, - removeRedundantAttributes: true, - useShortDoctype: true, - removeEmptyAttributes: true, - /* оставляем, поскольку у нас - * в элемент fm генерируеться - * таблица файлов - */ - removeEmptyElements: false, - removeOptionalTags: true, - removeScriptTypeAttributes: true, - removeStyleLinkTypeAttributes: true - }; - - - return htmlMinifier.minify(pData,lOptions); - }; - /*********************************/ - var final_code=html_minify(pData); - - var minFileName=pFileName.replace('.html','.min.html'); - - /* записываем сжатый html файл*/ - fs.writeFile(minFileName, final_code, fileWrited(minFileName)); - }; - - console.log('reading file ' + INDEX_HTML+'...'); - fs.readFile(INDEX_HTML,fileReaded(INDEX_HTML,dataReaded_f)); - - return true; -}; - -/* функция переводит картинки в base64 и записывает в css-файл*/ -function base64_images(pFileContent_s){ - 'use strict'; - var b64img; - try{ - b64img = require('css-b64-images'); - }catch(error){ - console.log('can\'n load clean-css \n' + - 'to use images to base64 convertation you need to install css-base64-images \n' + - 'npm install -g css-b64-images\n' + - 'https://github.com/Filirom1/css-base64-images'); - return false; - } - b64img.fromString(pFileContent_s, '.','', function(err, css){ - console.log('images converted to base64 and saved in css file'); - fs.writeFile(CSSDIR+'all.min.css', css, fileWrited('all.min.css')); - }); -} - -/* Функция создаёт асинхроную версию - * для чтения файла - * @pFileName - имя считываемого файла - */ -function fileReaded(pFileName,pCompressFunc){ - "use strict"; - return function(pError,pData){ - /* функция в которую мы попадаем, - * если данные считались - * - * если ошибка - показываем её - * иначе если переданная функция - - * функция запускаем её - */ - if(!pError) - if (pCompressFunc && typeof pCompressFunc==="function") - pCompressFunc(pFileName,pData.toString()); - else console.log(pError); - }; -} - -/* - * Функция вызываеться после записи файла - * и выводит ошибку или сообщает, - * что файл успешно записан - */ -function fileWrited(pFileName){ - "use strict"; - return function(error){ - console.log(error?error:('file '+pFileName+' writed...')); - }; -} \ No newline at end of file diff --git a/node_modules/.bin/jitsu b/node_modules/.bin/jitsu deleted file mode 120000 index ab860a6f..00000000 --- a/node_modules/.bin/jitsu +++ /dev/null @@ -1 +0,0 @@ -../jitsu/bin/jitsu \ No newline at end of file diff --git a/node_modules/.bin/nodester b/node_modules/.bin/nodester deleted file mode 120000 index aa4a5eb1..00000000 --- a/node_modules/.bin/nodester +++ /dev/null @@ -1 +0,0 @@ -../nodester-cli/bin/nodester.js \ No newline at end of file diff --git a/node_modules/jitsu b/node_modules/jitsu deleted file mode 120000 index d5540629..00000000 --- a/node_modules/jitsu +++ /dev/null @@ -1 +0,0 @@ -../../local/lib/node_modules/jitsu \ No newline at end of file diff --git a/node_modules/nodester-cli b/node_modules/nodester-cli deleted file mode 120000 index da254801..00000000 --- a/node_modules/nodester-cli +++ /dev/null @@ -1 +0,0 @@ -../../local/lib/node_modules/nodester-cli \ No newline at end of file diff --git a/node_modules/vcap b/node_modules/vcap deleted file mode 120000 index 38146ce0..00000000 --- a/node_modules/vcap +++ /dev/null @@ -1 +0,0 @@ -../../local/lib/node_modules/vcap \ No newline at end of file diff --git a/package.json b/package.json deleted file mode 100644 index 338fbd73..00000000 --- a/package.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "name": "cloudcmd", - "version": "0.0.1-11", - "scripts": { - "test": "sh test/test.sh", - "start": "server.js" - }, - "engines": { - "node": "0.6.x" - }, - "node": "0.8.1", - "subdomain": "cloudcmd" -} diff --git a/server.js b/server.js deleted file mode 100644 index 9e704d81..00000000 --- a/server.js +++ /dev/null @@ -1,684 +0,0 @@ -"use strict"; - -/* Обьект содержащий все функции и переменные - * серверной части Cloud Commander'а - */ -var CloudServer={ - /* функция, которая генерирует заголовки - * файлов, отправляемые сервером клиенту - */ - generateHeaders :function(){}, - /* функция высылает - * данные клиенту - */ - sendResponse :function(){}, - /* Структура содержащая функции, - * и переменные, в которых - * говориться о поддерживаемых - * браузером технологиях - */ - BrowserSuport :{}, - /* Обьект для работы с кэшем */ - Cashe :{}, - /* Обьект через который - * выполняеться сжатие - * скриптов и стилей - */ - Minify :{}, - /* Асоциативный масив обьектов для - * работы с ответами сервера - * высылаемыми на запрос о файле и - * хранащий информацию в виде - * Responces[name]=responce; - */ - Responses :{}, - - /* ПЕРЕМЕННЫЕ */ - /* Поддержка браузером JS*/ - NoJS :true, - /* Поддержка gzip-сжатия - * браузером - */ - Gzip :undefined, - - /* КОНСТАНТЫ */ - /* index.html */ - INDEX :'index.html', - /* name of direcotory with libs */ - LIBDIR :'./lib', - LIBDIRSERVER :'./lib/server', - Port :31337, /* server port */ - IP :'127.0.0.1' -}; - -/* - * Обьект для работы с кэшем - * аналог клиентского обьекта - * с тем отличием, что в нём - * будут храниться серверные - * данные, такие как файлы - * отдаваемые клиенту - * (файлы проэкта по большому - * счёту, для ускорения - * первичной загрузки) - */ -CloudServer.Cache={ - _allowed :true, /* приватный переключатель возможности работы с кэшем */ - /* данные в которых храняться файлы - * в формате <поле> : <значение> - * _data[name]=pData; - * одному имени соответствуют - * одни данные - */ - _data :{}, - - /* функция говорит можно ли работать с кэшем */ - isAllowed :(function(){ - return CloudServer.Cache._allowed; - }), - /* функция устанавливает возможность работать с кэшем */ - setAllowed :(function(pAllowed){ - CloudServer.Cache._allowed=pAllowed; - }), - /* Если доступен кэш - * сохраняем в него данные - */ - set :(function(pName, pData){ - if(CloudServer.Cache._allowed && pName && pData){ - CloudServer.Cache._data[pName]=pData; - } - }), - /* Если доступен Cache принимаем из него данные*/ - get :(function(pName){ - if(CloudServer.Cache._allowed && pName){ - return CloudServer.Cache._data[pName]; - } - else return null; - }), - - /* Функция очищает кэш*/ - clear :(function(){ - if(CloudServer.Cache._allowed){ - CloudServer.Cache._data={}; - } - }) -}; - -/* Обьект для сжатия скриптов и стилей - * по умолчанию - сжимаються - */ -CloudServer.Minify={ - /* приватный переключатель минимизации */ - _allowed :{css:true,js:true,html:true, img: true}, - - /* функция разрешает или - * запрещает минимизировать - * css/js/html - * @pAllowed: - структура, в которой - * передаються параметры - * минификации, вида - * {js:true,css:true,html:false; img:true} - * img отвечает за перевод картинок в base64 - * и сохранение их в css-файл - */ - setAllowed :(function(pAllowed){ - if(pAllowed){ - this._allowed.css=pAllowed.css; - this._allowed.js=pAllowed.js; - this._allowed.html=pAllowed.html; - this._allowed.img=pAllowed.img; - } - }), - - /* - * Функция минимизирует css/js/html - * если установлены параметры минимизации - */ - doit :(function(){ - if(this._allowed.css || - this._allowed.js || - this._allowed.html){ - var lMinify = require(CloudServer.LIBDIRSERVER+'/minify'); - - this.done.js=this._allowed.js?lMinify.jsScripts():false; - this.done.html=this._allowed.html?lMinify.html():false; - this.done.css=this._allowed.css?lMinify.cssStyles(this._allowed.img):false; - } - }), - /* свойство показывающее случилась ли ошибка*/ - done:{js: false,css: false, html:false} -}; - - -var LeftDir='/'; -var RightDir=LeftDir; -/* модуль для работы с путями*/ -var Path = require('path'); - -var Fs = require('fs'); /* модуль для работы с файловой системой*/ - -var Zlib; -/* node v0.4 not contains zlib - */ -try{ - Zlib = require('zlib'); /* модуль для сжатия данных gzip-ом*/ -}catch(error){ - Zlib=undefined; - console.log('to use gzip-commpression' + - 'you should install zlib module\n' + - 'npm install zlib'); -} -var CloudFunc = require(CloudServer.LIBDIR + - (CloudServer.Minify.done.js?/* если стоит минификация*/ - '/cloudfunc.min':/* добавляем сжатый - иначе обычный */ - '/cloudfunc')); /* модуль с функциями */ -/* конструктор*/ -CloudServer.init=(function(){ - /* Determining server.js directory - * and chang current process directory - * (usually /) to it. - * argv[1] - is always script name - */ - var lServerDir = Path.dirname(process.argv[1]); - console.log('current dir: ' + process.cwd()); - console.log('server dir: ' + lServerDir); - process.chdir(lServerDir); - - var lConfig={ - "cache" : {"allowed" : true}, - "minification" : { - "js" : true, - "css" : true, - "html" : true, - "img" : true - } - }; - try{ - console.log('reading configureation file config.json...'); - lConfig=require('./config'); - console.log('config.json readed'); - }catch(pError){ - console.log('warning: configureation file config.json not found...\n' + - 'using default values...\n' + - JSON.stringify(lConfig)); - } - - /* Переменная в которой храниться кэш*/ - CloudServer.Cache.setAllowed(lConfig.cache.allowed); - /* Change default parameters of - * js/css/html minification - */ - CloudServer.Minify.setAllowed(lConfig.minification); - /* Если нужно минимизируем скрипты */ - CloudServer.Minify.doit(); -}); - - -/* создаём сервер на порту 31337 */ -CloudServer.start=function() -{ - CloudServer.init(); - - /* constant ports of deployng servers - var lCloudFoundryPort = process.env.VCAP_APP_PORT; - var lNodesterPort = process.env.app_port; - var lC9Port = process.env.PORT; - */ - CloudServer.Port = process.env.PORT || /* c9 */ - process.env.app_port || /* nodester */ - process.env.VCAP_APP_PORT || /* cloudfoundry */ - CloudServer.Port; - - CloudServer.IP = process.env.IP || /* c9 */ - CloudServer.IP; - - var http = require('http'); - http.createServer(CloudServer._controller).listen( - CloudServer.Port, - CloudServer.IP); - - console.log('Cloud Commander server running at http://' + - CloudServer.IP + - ':' + - CloudServer.Port); - /* - (!lC9Port? - (!lCloudFoundryPort? - (!lNodesterPort?31337:lNodesterPort) - :lCloudFoundryPort) - :lC9Port)); - */ -}; - - -/* Функция создаёт заголовки файлов - * в зависимости от расширения файла - * перед отправкой их клиенту - * @pName - имя файла - * @pGzip - данные сжаты gzip'ом - */ -CloudServer.generateHeaders = function(pName, pGzip){ - var lType=''; - /* высылаем заголовок в зависимости от типа файла */ - /* если расширение у файла css - - * загружаем стили - */ - if(CloudFunc.checkExtension(pName,'css')) - lType='text/css'; - /* загружаем js */ - else if(CloudFunc.checkExtension(pName,'js')) - lType='text/javascript'; - /* загружаем картинки*/ - else if(CloudFunc.checkExtension(pName,'png')) - lType='image/png'; - /* загружаем json*/ - else if(CloudFunc.checkExtension(pName,'json')) - lType='application/json'; - else if(CloudFunc.checkExtension(pName,'html')) - lType='text/html'; - else if(CloudFunc.checkExtension(pName,'appcache')) - lType='text/cache-manifest'; - /* если это неизвестный тип файла - - * высылаем его просто как текст - */ - else lType='text/plain'; - - return { - /* if type of file any, but img - - * then we shoud specify charset - */ - 'Content-Type': lType + (lType.indexOf('img')<0?'; charset=UTF-8':''), - 'cache-control': 'max-age='+(31337*21), - 'last-modified': new Date().toString(), - 'content-encoding': pGzip?'gzip':'', - /* https://developers.google.com/speed/docs/best-practices/caching?hl=ru#LeverageProxyCaching */ - 'Vary': 'Accept-Encoding' - }; -}; - -/* - * Главная функция, через которую проихсодит - * взаимодействие, обмен данными с клиентом - * @req - запрос клиента (Request) - * @res - ответ сервера (Response) - */ -CloudServer._controller=function(pReq, pRes) -{ - /* Читаем содержимое папки, - переданное в url - */ - var url = require("url"); - var pathname = url.parse(pReq.url).pathname; - console.log('pathname: '+pathname); - - /* получаем поддерживаемые браузером кодировки*/ - var lAcceptEncoding = pReq.headers['accept-encoding']; - /* запоминаем поддерживает ли браузер - * gzip-сжатие при каждом обращении к серверу - * и доступен ли нам модуль zlib - */ - if (lAcceptEncoding && - lAcceptEncoding.match(/\bgzip\b/) && - Zlib){ - CloudServer.Gzip=true; - }else - CloudServer.Gzip=false; - /* путь в ссылке, который говорит - * что js отключен - */ - var lNoJS_s=CloudFunc.NOJS; - var lFS_s=CloudFunc.FS; - - if(pathname!=='/favicon.ico') - { - console.log("request for " + pathname + " received..."); - var lName; - - /* если в пути нет информации ни о ФС, - * ни об отсутствии js, - * ни о том, что это корневой - * каталог - загружаем файлы проэкта - */ - if(pathname.indexOf(lFS_s)<0 && - pathname.indexOf(lNoJS_s)<0 && - pathname!=='/'){ - /* если имена файлов проекта - загружаем их*/ - /* убираем слеш и читаем файл с текущец директории*/ - //lName=Path.basename(pathname); - - /* добавляем текующий каталог к пути */ - lName='.'+pathname; - console.log('reading '+lName); - /* сохраняем указатель на responce и имя */ - CloudServer.Responses[lName]=pRes; - - /* Берём значение из кэша - * сжатый файл - если gzip-поддерживаеться браузером - * не сжатый - в обратном случае - */ - var lFileData=CloudServer.Cache.get(CloudServer.Gzip?(lName+'_gzip'):lName); - - var lReadFileFunc_f=CloudServer.getReadFileFunc(lName); - /* если там что-то есть передаём данные в функцию - * readFile - */ - if(lFileData){ - console.log('readed from cache'); - /* передаём данные с кэша, - * если gzip включен - сжатые - * в обратном случае - несжатые - */ - lReadFileFunc_f(undefined,lFileData,true); - } - else Fs.readFile(lName,lReadFileFunc_f); - - }else{/* если мы имеем дело с файловой системой*/ - /* если путь не начинаеться с no-js - значит - * js включен - */ - /* убираем пометку cloud, без которой c9.io - * не работает поскольку путь из двух слешей - * (/fs/no-js/) - очень короткий, нужно - * длиннее - */ - - if(pathname.indexOf(lNoJS_s)!==lFS_s.length && pathname!=='/'){ - CloudServer.NoJS=false; - }else pathname=pathname.replace(lNoJS_s,''); - - /* убираем индекс файловой системы */ - if(pathname.indexOf(lFS_s)===0){ - pathname=pathname.replace(lFS_s,''); - /* если посетитель только зашел на сайт - * no-js будет пустым, как и fs - */ - /* если в пути нету fs - посетитель только зашел на сайт - * загружаем его полностью. - */ - }else CloudServer.NoJS=true; - /* если в итоге путь пустой - * делаем его корневым - */ - if(pathname==='')pathname='/'; - - RightDir=pathname; - LeftDir=pathname; - - /* если встретиться пробел - - * меня код символа пробела на пробел - */ - - LeftDir=CloudFunc.replaceSpaces(LeftDir); - RightDir=CloudFunc.replaceSpaces(RightDir); - - /* Проверяем с папкой ли мы имеем дело */ - - /* читаем сновные данные о файле */ - var lStat; - try{ - lStat=Fs.statSync(LeftDir); - }catch(error){ - console.log(error); - CloudServer.Responses[LeftDir]=pRes; - CloudServer.sendResponse('OK',error.toString(),LeftDir); - } - /* если это каталог - - * читаем его содержимое - */ - try{ - /* если установлено сжатие - * меняем название html-файла и - * загружаем сжатый html-файл в дальнейшем - */ - CloudServer.INDEX=(CloudServer.Minify.done.html?'index.min.html':CloudServer.INDEX); - /* - * сохраним указатель на response - */ - CloudServer.Responses[CloudServer.INDEX]=pRes; - if(lStat.isDirectory()) - Fs.readdir(LeftDir,CloudServer._readDir); - /* отдаём файл */ - else if(lStat.isFile()){ - CloudServer.Responses[LeftDir]=pRes; - Fs.readFile(LeftDir,CloudServer.getReadFileFunc(LeftDir)); - console.log('reading file: '+LeftDir); - } - }catch(error){console.log(error);} - } - } -}; - -/* Функция читает ссылку или выводит информацию об ошибке*/ -CloudServer._readDir=function (pError, pFiles) -{ - if(!pError) - { - /* данные о файлах в формате JSON*/ - var lJSON=[]; - var lJSONFile={}; - /* Если мы не в корне добавляем слеш к будующим ссылкам */ - if(LeftDir!=='/') - { - RightDir+='/'; - LeftDir+='/'; - } - - pFiles=pFiles.sort(); - - lJSON[0]={path:LeftDir,size:'dir'}; - var fReturnFalse=function returnFalse(){return false;}; - for(var i=0;i','') - .replace('style.css','all.min.css') - :lIndex; - - lIndex = CloudServer.Minify.done.js?lIndex.replace('client.js','client.min.js'):lIndex; - - lIndex=lIndex.toString().replace('
    ','
    '+lList); - /* меняем title */ - lIndex=lIndex.replace('Cloud Commander', - ''+CloudFunc.setTitle()+''); - /* отображаем панель быстрых клавишь */ - lList=lIndex; - /* если браузер поддерживает gzip-сжатие*/ - lHeader=CloudServer.generateHeaders('text/html',CloudServer.Gzip); - }catch(error){console.log(error);} - }else{ - /* в обычном режиме(когда js включен - * высылаем json-структуру файлов - * с соответствующими заголовками - */ - lList=JSON.stringify(lJSON); - lHeader=CloudServer.generateHeaders('application/json',CloudServer.Gzip); - } - /* если браузер поддерживает gzip-сжатие - сжимаем данные*/ - if(CloudServer.Gzip){ - Zlib.gzip(lList,CloudServer.getGzipDataFunc(lHeader,CloudServer.INDEX)); - } - /* если не поддерживаеться - отсылаем данные без сжатия*/ - else - CloudServer.sendResponse(lHeader,lList,CloudServer.INDEX); - } - else - { - console.log(pError); - CloudServer.sendResponse('OK',pError.toString()); - } -}; - -/* Функция генерирует функция считывания файла - * таким образом, что бы у нас было - * имя считываемого файла - * @pName - полное имя файла - */ -CloudServer.getReadFileFunc = function(pName){ -/* - * @pError - ошибка - * @pData - данные - * @pFromFile - прочитано с файла bool - */ - var lReadFile=function(pError,pData,pFromCache_b){ - if (!pError){ - console.log('file ' + pName + ' readed'); - - /* берём из кэша данные файла - * если их нет в кэше - - * сохраняем - */ - if(!pFromCache_b && CloudServer.Cache.isAllowed) - CloudServer.Cache.set(pName,pData); - /* если кэш есть - * сохраняем его в переменную - * которая до этого будет пустая - * по скольку мы будем вызывать этот метод - * сами, ведь файл уже вычитан - */ - - var lHeader=CloudServer.generateHeaders(pName,CloudServer.Gzip); - /* если браузер поддерживает gzip-сжатие - сжимаем данные*/ - if(CloudServer.Gzip &&!pFromCache_b){ - /* сжимаем содержимое */ - Zlib.gzip(pData,CloudServer.getGzipDataFunc(lHeader,pName)); - } - else{ - /* высылаем несжатые данные */ - CloudServer.sendResponse(lHeader,pData,pName); - } - } - else - { - console.log(pError.path); - if(pError.path!=='passwd.json') - { - console.log(pError); - CloudServer.sendResponse('OK',pError.toString(),pName); - }else{ - CloudServer.sendResponse('OK','passwd.json'); - } - } - }; - return lReadFile; -}; - -/* Функция получает сжатые данные - * @pHeader - заголовок файла - */ -CloudServer.getGzipDataFunc=function(pHeader,pName){ - return function(error,pResult){ - if(!error){ - /* отправляем сжатые данные - * вместе с заголовком - */ - /* если установлена работа с кэшем - * сохраняем сжатые данные - */ - if(CloudServer.Cache.isAllowed){ - /* устанавливаем кєш */ - console.log(pName+' gziped'); - CloudServer.Cache.set(pName+'_gzip',pResult); - } - CloudServer.sendResponse(pHeader,pResult,pName); - } - else{ - console.log(error); - CloudServer.sendResponse(pHeader,error); - } - }; -}; -/* Функция высылает ответ серверу - * @pHead - заголовок - * @pData - данные - * @pName - имя отсылаемого файла - */ -CloudServer.sendResponse = function(pHead, pData,pName){ - /* если у нас есть указатель на responce - * для соответствующего файла - - * высылаем его - */ - var lResponse=CloudServer.Responses[pName]; - if(lResponse){ - lResponse.writeHead(200,pHead); - lResponse.end(pData); - console.log(pName+' sended'); - } -}; - -CloudServer.start(); \ No newline at end of file diff --git a/test/test.sh b/test/test.sh deleted file mode 100644 index 9ad8c6e2..00000000 --- a/test/test.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/sh -npm i jshint -g -echo "jshint server.js client.js lib/cloudfunc.js" -jshint --config ./.jshintrc ./server.js ./client.js -echo "jshint ./lib/cloudfunc.js ./lib/server/minify.js ./lib/client/keyBinding.js" -jshint --config ./.jshintrc ./lib/cloudfunc.js ./lib/server/minify.js ./lib/client/keyBinding.js \ No newline at end of file From a4db4856fe086fd019de9da1f7b28994dd10c719 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Thu, 5 Jul 2012 04:08:15 -0400 Subject: [PATCH 32/32] full reload --- README.md | 53 +++ client.js | 713 +++++++++++++++++++++++++++++++++++++++ config.json | 9 + css/reset.css | 72 ++++ css/style.css | 318 +++++++++++++++++ img/console_clear.png | Bin 0 -> 1344 bytes img/dir.png | Bin 0 -> 537 bytes img/panel_refresh.png | Bin 0 -> 872 bytes img/spinner.gif | Bin 0 -> 1569 bytes img/txt.png | Bin 0 -> 294 bytes index.html | 54 +++ lib/README.md | 5 + lib/client/keyBinding.js | 248 ++++++++++++++ lib/cloudfunc.js | 504 +++++++++++++++++++++++++++ lib/server/minify.js | 279 +++++++++++++++ package.json | 7 + server.js | 684 +++++++++++++++++++++++++++++++++++++ test/test.sh | 6 + 18 files changed, 2952 insertions(+) create mode 100644 README.md create mode 100644 client.js create mode 100644 config.json create mode 100644 css/reset.css create mode 100644 css/style.css create mode 100644 img/console_clear.png create mode 100644 img/dir.png create mode 100644 img/panel_refresh.png create mode 100644 img/spinner.gif create mode 100644 img/txt.png create mode 100644 index.html create mode 100644 lib/README.md create mode 100644 lib/client/keyBinding.js create mode 100644 lib/cloudfunc.js create mode 100644 lib/server/minify.js create mode 100644 package.json create mode 100644 server.js create mode 100644 test/test.sh diff --git a/README.md b/README.md new file mode 100644 index 00000000..fc55b9af --- /dev/null +++ b/README.md @@ -0,0 +1,53 @@ +Cloud Commander [![Build Status](https://secure.travis-ci.org/coderaiser/cloudcmd.png?branch=master)](http://travis-ci.org/coderaiser/cloudcmd) +=============== +**Cloud Commander** - two-panels file manager, totally writed on js. +View [demo](http://demo-cloudcmd.cloudfoundry.com/ "demo"), [mirror](http://cloudcmd.nodester.com/ "mirror"). + +Google PageSpeed Score : [100](https://developers.google.com/speed/pagespeed/insights#url=http_3A_2F_2Fdemo-cloudcmd.cloudfoundry.com_2F&mobile=false "score") (out of 100). + +Benefits +--------------- +- full browser compatibility *(ie6+,chrome,safari,opera,firefox)*; +- responsible design +- one full page loading, *and then just one-time json-dir-listings loading +(with refresh opportunity).* +- caching readed directories *to localStorage (for now) +(so if network will disconnected or something heppen with a signal, we +definitely will can work cached copy of directory listings)*; +- key binding +- disabled js support *(working in limited mode)*. +- automated minification *client js-files and onstart-reading Cloud manager files on server starting.* + +**Cloud Commander** uses all benefits of js, so if js is disabled, +we moves to *limited mode*. + +Limited-mode features: +--------------- +- only 1 panel available +- no keybinding +- no local caching +- full loading of all web page(with styles, js-scripts, html-page etc). + +Hot keys: +--------------- +In all modern web browsers (but not in IE, becouse he special) hot keys works. +There is a short list: +- Ctrl + r - reload dir content +- Ctrl + d - clear local cache (wich contains dir contents) +- Alt + q - disable key bindings +- Alt + s - get all key bindings back +- up, down, enter - filesystem navigation + +Additional modules: +--------------- +**Cloud Commander** not using additional modules for main functionality. +But for minification and optimization tricks optional can be +assingned (and installed) modules: +- [UglifyJS] (https://github.com/mishoo/UglifyJS) +- [clean-css] (https://github.com/GoalSmashers/clean-css) +- [html-minifier] (https://github.com/kangax/html-minifier) +- [css-b64-images] (https://github.com/Filirom1/css-base64-images) + +Install addtitional modules: + + npm i uglify-js clean-css html-minifier css-b64-images \ No newline at end of file diff --git a/client.js b/client.js new file mode 100644 index 00000000..c5c669c3 --- /dev/null +++ b/client.js @@ -0,0 +1,713 @@ +/* Функция которая возвратит обьект CloudCommander + * @window - обьект window + * @document - обьект document + * @CloudFunc - обьект содержащий общий функционал + * клиентский и серверный + */ + +var CloudCommander=(function(){ +"use strict"; + +/* Клиентский обьект, содержащий функциональную часть*/ +var CloudClient={ + /* Конструктор CloudClient, который + * выполняет весь функционал по + * инициализации + */ + init :function(){}, + + keyBinding :function(){},/* функция нажатий обработки клавишь */ + keyBinded :false,/* оброботка нажатий клавишь установлена*/ + _loadDir :function(){}, + /* + * Функция привязываеться ко всем ссылкам и + * загружает содержимое каталогов + */ + /* Обьект для работы с кэшем */ + Cashe :{}, + + /* ПРИВАТНЫЕ ФУНКЦИИ */ + /* функция загружает json-данные о файловой системе */ + _ajaxLoad :function(){}, + /* Функция генерирует JSON из html-таблицы файлов */ + _getJSONfromFileTable :function(){}, + /* функция меняет ссыки на ajax-овые */ + _changeLinks :function(){}, + /* ОБЬЕКТЫ */ + /* обьект, который содержит функции для отображения картинок*/ + _images :{}, + /* КОНСТАНТЫ*/ + /* название css-класа текущего файла*/ + CURRENT_FILE :'current-file', + LIBDIR :'/lib', + LIBDIRCLIENT :'/lib/client' +}; + +/* + * Обьект для работы с кэшем + * в него будут включены функции для + * работы с LocalStorage, webdb, + * idexed db etc. + */ +CloudClient.Cache={ + _allowed :true, /* приватный переключатель возможности работы с кэшем */ + /* функция проверяет возможно ли работать с кэшем каким-либо образом */ + isAllowed :function(){}, + /* Тип кэша, который доступен*/ + type :{}, + /* Функция устанавливает кэш, если выбранный вид поддерживаеться браузером*/ + set :function(){}, + /* Функция достаёт кэш, если выбранный вид поддерживаеться браузером*/ + get :function(){}, + /* функция чистит весь кэш для всех каталогов*/ + clear :function(){} +}; + +/* Обьект, который содержит + * функции для отображения + * картинок + */ +CloudClient._images={ + /* Функция создаёт картинку загрузки*/ + loading :function(){ + var e=document.createElement('span'); + e.className='icon loading'; + e.id='loading-image'; + return e; +}, + + /* Функция создаёт картинку ошибки загрузки*/ + error :function(){ + var e=document.createElement('span'); + e.className='icon error'; + e.id='error-image'; + return e; + } +}; + +/* функция проверяет поддерживаеться ли localStorage */ +CloudClient.Cache.isAllowed=(function(){ + if(window.localStorage && + localStorage.setItem && + localStorage.getItem){ + CloudClient.Cache._allowed=true; + }else + { + CloudClient.Cache._allowed=false; + /* загружаем PolyFill для localStorage, + * если он не поддерживаеться браузером + * https://gist.github.com/350433 + */ + /* + CloudClient.jsload('https://raw.github.com/gist/350433/c9d3834ace63e5f5d7c8e1f6e3e2874d477cb9c1/gistfile1.js', + function(){CloudClient.Cache._allowed=true; + }); + */ + } +}); + /* если доступен localStorage и + * в нём есть нужная нам директория - + * записываем данные в него + */ +CloudClient.Cache.set=(function(pName, pData){ + if(CloudClient.Cache._allowed && pName && pData){ + localStorage.setItem(pName,pData); + } +}); +/* Если доступен Cache принимаем из него данные*/ +CloudClient.Cache.get=(function(pName){ + if(CloudClient.Cache._allowed && pName){ + return localStorage.getItem(pName); + } + else return null; +}); +/* Функция очищает кэш*/ +CloudClient.Cache.clear=(function(){ + if(CloudClient.Cache._allowed){ + localStorage.clear(); + } +}); + + +/* функция обработки нажатий клавишь */ +CloudClient.keyBinding=(function(){ + /* loading keyBinding module and start it */ + CloudClient.jsload(CloudClient.LIBDIRCLIENT+'/keyBinding.js',function(){ + CloudCommander.keyBinding(); + }); +}); + + +/* + * Функция привязываеться ко всем ссылкам и + * загружает содержимое каталогов + */ +CloudClient._loadDir=(function(pLink,pNeedRefresh){ + /* @pElem - элемент, + * для которого нужно + * выполнить загрузку + */ + return function(){ + /* показываем гиф загрузки возле пути папки сверху*/ + LoadingImage.className='icon loading';/* показываем загрузку*/ + ErrorImage.className='icon error hidden';/* прячем ошибку */ + /* если элемент задан - + * работаем с ним + */ + /* если мы попали сюда с таблицы файлов*/ + try{ + this.firstChild.nextSibling.appendChild(LoadingImage); + }catch(error){ + /* если + + * кнопка обновления + */ + try{this.firstChild.parentElement.appendChild(LoadingImage);} + catch(error){console.log(error);} + } + + var lCurrentFile=document.getElementsByClassName(CloudClient.CURRENT_FILE); + /* получаем имя каталога в котором находимся*/ + var lHref; + try{ + lHref=lCurrentFile[0].parentElement.getElementsByClassName('path')[0].textContent; + }catch(error){console.log('error');} + + lHref=CloudFunc.removeLastSlash(lHref); + var lSubstr=lHref.substr(lHref,lHref.lastIndexOf('/')); + lHref=lHref.replace(lSubstr+'/',''); + + /* загружаем содержимое каталога*/ + CloudClient._ajaxLoad(pLink, pNeedRefresh); + + /* получаем все элементы выделенной папки*/ + /* при этом, если мы нажали обновить + * или +R - ссылок мы ненайдём + * и заходить не будем + */ + var lA=this.getElementsByTagName('a'); + /* если нажали на ссылку на верхний каталог*/ + if(lA.length>0 && lA[0].textContent==='..' && + lHref!=='/'){ + /* функция устанавливает курсор на каталог + * с которого мы пришли, если мы поднялись + * в верх по файловой структуре + */ + CloudClient._currentToParent(lHref); + } + + /* что бы не переходить по ссылкам + * а грузить всё ajax'ом, + * возвращаем false на событие + * onclick + */ + return false; + }; + }); + +/* Функция устанавливает текущим файлом, тот + * на который кликнули единожды + */ +CloudClient._setCurrent=(function(){ + /* + * @pFromEnter - если мы сюда попали + * из события нажатия на энтер - + * вызоветься _loadDir + */ + return function(pFromEnter){ + var lCurrentFile=document.getElementsByClassName(CloudClient.CURRENT_FILE); + if(lCurrentFile && lCurrentFile.length > 0){ + /* если мы находимся не на + * пути и не на заголовках + */ + if(this.className!=='path' && + this.className!=='fm_header'){ + + lCurrentFile[0].className=''; + /* устанавливаем курсор на файл, + * на который нажали */ + this.className=CloudClient.CURRENT_FILE; + } + } + /* если мы попали сюда с энтера*/ + if(pFromEnter===true){ + this.ondblclick(this); + }/* если мы попали сюда от клика мышки */ + else{pFromEnter.returnValue=false;} + + /* что бы не переходить по ссылкам + * а грузить всё ajax'ом, + * возвращаем false на событие + * onclick + */ + return false; + }; + }); + +/* функция устанавливает курсор на каталог + * с которого мы пришли, если мы поднялись + * в верх по файловой структуре + * @pDirName - имя каталога с которого мы пришли + */ +CloudClient._currentToParent = (function(pDirName){ + /* опредиляем в какой мы панели: + * правой или левой + */ + var lCurrentFile=document.getElementsByClassName(CloudClient.CURRENT_FILE); + var lPanel; + try{ + lPanel=lCurrentFile[0].parentElement.id; + }catch(error){console.log("Current file not found\n"+error);} + /* убираем слэш с имени каталога*/ + pDirName=pDirName.replace('/',''); + /* ищем файл с таким именем*/ + lPanel=document.getElementById(lPanel); + if(!lPanel)return; + + var lLi=lPanel.getElementsByTagName('li'); + for(var i=0;i0)lCurrentFile[0].className=''; + + lLi[i].className=CloudClient.CURRENT_FILE; + } + } +}); + +/* глобальные переменные */ +var LoadingImage; +var ErrorImage; + +var $; +var CloudFunc; +/* Конструктор CloudClient, который + * выполняет весь функционал по + * инициализации + */ +CloudClient.init=(function() +{ + /* меняем title + * если js включен - имена папок отображать необязательно... + * а может и обязательно при переходе, можно будет это сделать + */ + var lTitle=document.getElementsByTagName('title'); + if(lTitle.length>0)lTitle[0].textContent='Cloud Commander'; + + /* загружаем jquery: */ + CloudClient.jsload('//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js',function(){ + /* сохраняем переменную jQuery себе в область видимости */ + $=window.jQuery; + if(!window.jQuery)CloudClient.jsload('jquery.min.js', + function(){ + $=window.jQuery; + }); + }); + + /* загружаем общие функции для клиента и сервера*/ + CloudClient.jsload(CloudClient.LIBDIR+'/cloudfunc.js',function(){ + /* берём из обьекта window общий с сервером функционал */ + CloudFunc=window.CloudFunc; + + /* меняем ссылки на ajax'овые*/ + CloudClient._changeLinks(CloudFunc.LEFTPANEL); + CloudClient._changeLinks(CloudFunc.RIGHTPANEL); + + /* устанавливаем переменную доступности кэша*/ + CloudClient.Cache.isAllowed(); + /* Устанавливаем кэш корневого каталога */ + if(!CloudClient.Cache.get('/'))CloudClient.Cache.set('/',CloudClient._getJSONfromFileTable()); + } + ); + + LoadingImage=CloudClient._images.loading(); + /* загружаем иконку загрузки возле кнопки обновления дерева каталогов*/ + try{ + document.getElementsByClassName('path')[0].getElementsByTagName('a')[0].appendChild(LoadingImage); + LoadingImage.className+=' hidden'; /* прячем её */ + }catch(error){console.log(error);} + ErrorImage=CloudClient._images.error(); + + /* устанавливаем размер высоты таблицы файлов + * исходя из размеров разрешения экрана + */ + + /* формируем и округляем высоту экрана + * при разрешениии 1024x1280: + * 658 -> 700 + */ + + var lHeight=window.screen.height - (window.screen.height/3).toFixed(); + lHeight=(lHeight/100).toFixed()*100; + + var lFm=document.getElementById('fm'); + if(lFm)lFm.style.cssText='height:' + + lHeight + + 'px'; + + /* выделяем строку с первым файлом */ + var lFmHeader=document.getElementsByClassName('fm_header'); + if(lFmHeader && lFmHeader[0].nextSibling) + lFmHeader[0].nextSibling.className=CloudClient.CURRENT_FILE; + + /* показываем элементы, которые будут работать только, если есть js */ + var lFM=document.getElementById('fm'); + if(lFM)lFm.className='localstorage'; + + /* если есть js - показываем правую панель*/ + var lRight=document.getElementById('right'); + if(lRight)lRight.className=lRight.className.replace('hidden',''); + + CloudClient.cssSet({id:'show_2panels', + element:document.head, + inner:'#left{width:46%;}' + }); +}); + +/* функция меняет ссыки на ajax-овые */ +CloudClient._changeLinks = function(pPanelID) +{ + /* назначаем кнопку очистить кэш и показываем её*/ + var lClearcache=document.getElementById('clear-cache'); + if(lClearcache)lClearcache.onclick=CloudClient.Cache.clear; + + /* меняем ссылки на ajax-запросы */ + var lPanel=document.getElementById(pPanelID); + var a=lPanel.getElementsByTagName('a'); + + /* Если нажмут на кнопку перезагрузить страниц - её нужно будет обязательно + * перезагрузить + */ + /* номер ссылки очистки кэша*/ + //var lCLEARICON=0; + /* номер ссылки иконки обновления страницы */ + var lREFRESHICON=0; + + /* путь в ссылке, который говорит + * что js отключен + */ + var lNoJS_s = CloudFunc.NOJS; + var lFS_s = CloudFunc.FS; + + for(var i=0;i=3){ + element.onload=pFunc; + if(arguments.length>=4){ + element.style.cssText=pStyle; + } + } + //document.body + pElement.appendChild(element); + return element;//'elem '+src+' loaded'; + } + /* если js-файл уже загружен + * запускаем функцию onload + */ + else if(pFunc){ + try{ + pFunc(); + }catch(error){console.log(error);} + } +}; + +/* Функция загружает js-файл */ +CloudClient.jsload = function(pSrc,pFunc,pStyle,pId) +{ + CloudClient._anyload('script',pSrc,pFunc,pStyle,pId,document.body); +}; +/* Функция создаёт елемент style и записывает туда стили + * @pParams_o - структура параметров, заполняеться таким + * образом: {src: ' ',func: '', id: '', element: '', inner: ''} + * все параметры опциональны + */ +CloudClient.cssSet = function(pParams_o){ + var lElem=CloudClient._anyload('style', + pParams_o.src, + pParams_o.func, + pParams_o.style, + pParams_o.id, + pParams_o.element?pParams_o.element:document.body); + lElem.innerHTML=pParams_o.inner; +}; + +/* + * Функция генерирует JSON из html-таблицы файлов + */ +/* + * Используеться при первом заходе в корень + */ +CloudClient._getJSONfromFileTable=function() +{ + var lLeft=document.getElementById('left'); + var lPath=document.getElementsByClassName('path')[0].textContent; + var lFileTable=[{path:lPath,size:'dir'}]; + var lLI=lLeft.getElementsByTagName('li'); + + var j=1;/* счётчик реальных файлов */ + var i=1;/* счётчик элементов файлов в DOM */ + /* Если путь отличный от корневного + * второй элемент li - это ссылка на верхний + * каталог '..' + */ + i=2;/* пропускам Path и Header*/ + + + for(;ili{ + margin:10px; + } + /* если правая панель не помещаеться - прячем её */ + #right{ + display:none; + } + /* текущий файл под курсором */ + .current-file{ + background-color: rgba(49, 123, 249, .40); + color:white; + } + /* делаем иконки под курсом белыми*/ + .current-file > .mini-icon{ + color:white; + } + .current-file > .text-file::before{ + color:white; + } + +/* меняем иконки на шрифтовые*/ + .mini-icon { + font: 60px 'Octicons Regular'; + width: 40%; + height: 0; + margin-left: 0; + float: right; + position: relative; + top: -17px; + + color: rgba(246, 224, 124, 0.56); + } + .directory::before{ + content: '\f216'; + } + .text-file::before{ + color: rgba(26, 224, 124, 0.56); + content: '\f211'; + } + .text-file{ + background-image:none; + } + + /* убираем заголовок*/ + .fm_header{ + display:none; + } + .mode,.size,.owner{ + /* располагаем элементы + * один под другим + */ + display: table; + float: none; + width: 0; + + text-align: left; + } + /* выводим заголовки рядом с полями */ + .name::before{ + content: 'name:'; + font-weight: bold; + font-size: 13px; + } + .mode::before{ + content: 'mode:'; + font-weight: bold; + font-size: 13px; + } + .size::before{ + content: 'size:'; + font-weight: bold; + font-size: 13px; + } + .owner::before{ + content: 'owner:'; + font-weight: bold; + font-size: 13px; + } + + .name{ + float: none; + width:100%; + font-size: 18px; + } +} +@media only screen and (min-width: 601px) and (max-width: 785px){ + #left{ + width:90% !important; + } + #right{ + display:none; + } +} + +@media only screen and (min-width:786px) and (max-width: 1155px){ + #left{ + width:90% !important; + } + /* если правая панель не помещаеться - прячем её */ + #right{ + display:none; + } +} \ No newline at end of file diff --git a/img/console_clear.png b/img/console_clear.png new file mode 100644 index 0000000000000000000000000000000000000000..f5739eb13b9c313415b984ea96ad47505c9dd7e7 GIT binary patch literal 1344 zcmV-G1;6@1^@s6nD_O6000FCNkl-&xG_lrq5JXm++URcxOi=C%>~R;c#Bt8S0&&E5Hja3i;IivGcz-!xw-j(mw07mC2V0~ z;XtF&kmcp&X`H*^e0_3qlBm^n#Mjqvm9rQk$K>SX*p`+S-N?uYnV6U$80qo&_&BMp zttAqP^fB7Ga1t*qEzyzgK=6S~7W7+VVo$x&rxRZ3u> zOfScE{m9YoW0S?0$3N@qAL;O@dpS8dq`SMD^z`)5`8}$rs7MJ22;8Le+tk!Vu3vvI z!(?$5Q{(>hy!xq2Yfi<$MlV3 zT(1d)LSa0e6z&A(cxnx<{$qoV*c^ZBIXzWY+~N=&nD&_|7>F3@y{ma9sg`% zp7GBv<{ba5Vh0BYDz-33{2R73oW26NTrQ=B!yNH%C_rJHCaU_N5N$qE32|%B{f#-~q%u@n9U*FL(UAf;`X*zUN6V z<8U>IJwOj=0A-*E6mq19>D$1#!~$z;>#y)d1+u|sKmpP?qM&^lM>(AL1(ueURrCUj zkjo9S;H(zlCHRhtkKcY4a$k%l#EkQ#5UTfsHptZ)KoQUfYM01MdQDrp+WnM zQ5ORId5$zbKE8NvZcdBHqA~T0L?Zbb<#fvs|CcU#Z=USKDt2~u&OpRJG>-rI`FWio z{(XFWwry-|vN(z3;^K;t)K8L! z1qDAfj(;RHYWJhlfWT z+1Z`>#$@sN^R82wnVC~+wR+#%+j~1dKYzeZ^;+}vH<;Abqg4LpGk(!VfLrag-ol_>97 zTiVgl@qtM6>Z($y98{?)v>c=gIKLH$M54RTD?(0A&fOO;zP@dul%mu-QCuY0K^f*M zn{cI5r#}9%ZhhU|-9NImwN2$)=xJZ-psrJm|9=3w$r4qVmLG}$0000x(K@^6+>g^d@v4;gkbWsEoXE%32*i1tcpTNXd5CcIl)ECgqz|2rE6EW}s7R?kl za1q`0GCkMruC6-2LANtwVlsgzsp4?{@7$`KBv!G66>Vie3h?3OmEEkjwdLG0PgLVi z`!N((f$A@n17Ldj#`};0I3@iHJ5M{#IZz|UIYRm4(!uV7eYIYIwQf&}_2J~}>pQ^n z6o8--^T(=hkBNQ_k{-_GWE;FMW7!p}f{NG3nHZ{D5<3d8&tLh%a4AqqnjMkr3m&fkMdECD3N5}Unig5wy40;>lo4j~k+e}v)` zR6)J8Mk*u=SpB`p6o)7j?S0T@9?bz#m@l>gc*zk__|*!FMcHwP!gwLJvS~9c0px8E zW-!=9%H93I*%*Z8=x$dA&dD~$D#ws+K{GQN()gz!9L&jK+m?%ta#Ng#%LpbBNoY3B#?};^W4ea|M9+}o zHdC0d@8fOgzx&s(hgNN>reIf=V)iIwe@=tlS^Z^U*t?c$nwvM@PHQ5tkP zH-)B-Mq`7fP!!Eyd~nL83rQ4)|3~a@{N+69jegYHY3LuZxR?j&Rg( zPR07x9`1ZD#|O8G-ntj8_HQXyY9i(tVWd9NjbO4rIv&%;esZ6qJG=idk${yrEWlMrvxH7xey@*#~8ywwu|0 z)svn+awvo8ooru?o>KJ^1|_LLspI?9dj{jttL3#^3xM*lrKE|^FL5>V|Z6PM$qllk=|_^ZK-V(${mTKO4ZY-M}wa6qM=bJ@09jxyC2Hc zBF@xIj+>6SwwiwW(&F$#Y3Sl-!9sR+nMfeV>u)|N(^D%|{T_ab#w7d}0-RCWfL>r2Y@ZJK_=UpZo#K^zc-BA}1#R0000g($p8XB6Knwp!NTUuILTU)PQz1r5+*52N3GMT!%x_Wwg zdV6~Z1_lNP2Zx4+hKGkoMn*dAeCMNFOxidLAIW;vkJv}`$GxOlVgU62_ zKY8-x>C>lkb8`y|3yX`3OG``3%gZY(E32!kYiny}v-#!Am+R~6ymi9X@OZ5|=$3Ac*%IgT+Ds5+OGdk_-B4F{dAcdAsVTz+%sNqp=LM4kzb?{0I z;Bz=G_C%7MC{enBL1!z)8|7O>CCWe^*>Uq0Hiat%awm$Q!Y#nx%ULG0cP#MSC7}pi znBEk3;4eG{f*4FWj|O%l84+(L?P{oSw#38uvnG)ZZ+hDkFoWN&DomB1{ zjl0?f$RtSX%!3ZVRRQYWApJ;=oN@V{ch5`Pp%I(?a3*b!(AJ-(x=?je>q56RP z`&&@0ahx7+72}@1-1+BKffxy;hb*QAAxO|FHP9nNxoauxL_2-NktKHRL3+tnwy?RjN$+Zicb zGBLx;8e@gaVDK}69D|}nX@oXnI|!S}2JYnGOe3(s;UE-Jn;n9SGu=fL!)KMH3elT) zq@5g&on39$(Z3#Ol<^%)PSXVo@E&q6`cSTrjO&%y`>vBZRF7tVaM(pbqh&-VhzUFx zAqs1hWVaY)*e%^*0kMXxkk*L*^>%P&;+jFh5-IyB8C89Gd22-x+jxV%#Di|LEwkjyu(vg~l-y8JRso0YmVQ5EkVH9_bWdmriPn;Xz0HU?r-}Ym*JU~Gu z#H!z-Sig~NtEtil^EbXk5q|z4muDm>JIP0rwG7WD3S+9GBJ~;heG|L%tnJOt3;ODZ z-=AxhB~Tm|@--{&wt!9Dq!z~jdjgQsj;d1ui)`r{g#3l@`Y+o|m4+ohb8%lK3Tosj z`cr?TkjIV;SJxUp<&q1u2@0f zfjG4{K?pdGK(syql%&93%2zra#Xu0BrOCKFA;`ks$&+C#5QQ<|d}62BjvZR2H60wE-&H;pyTSqH(@-Vl>|&1p(LP>kg~E zYiz5X^`c$+%8#zC{u)yfe-5 zmgid={Z3k(ERKCKrE7DF;=x4^O+ pzO8rLO8p|Ip=x)jHOtWj`bJBmKdh_V<`47(gQu&X%Q~loCIFbEay|e6 literal 0 HcmV?d00001 diff --git a/index.html b/index.html new file mode 100644 index 00000000..6524a912 --- /dev/null +++ b/index.html @@ -0,0 +1,54 @@ + + + + + + + Cloud Commander + + + + + + + + + + +
    +
    + + + + \ No newline at end of file diff --git a/lib/README.md b/lib/README.md new file mode 100644 index 00000000..a741f80c --- /dev/null +++ b/lib/README.md @@ -0,0 +1,5 @@ +Cloud Commander Libraries +=============== +**Cloud Commander Libraries** - dir thet contains scripts, thet uses +on client and server side, and modules, wich is not necessary +for CloudCommander work, but they adds some sugor. \ No newline at end of file diff --git a/lib/client/keyBinding.js b/lib/client/keyBinding.js new file mode 100644 index 00000000..a441671f --- /dev/null +++ b/lib/client/keyBinding.js @@ -0,0 +1,248 @@ +var CloudCommander; +var CloudFunc; +CloudCommander.keyBinding=(function(){ + "use strict"; + var key_event=function(event){ + /* + * Делаем допущение что перезагружать Cloud Commander + * посетителям не придёться, в любом случае, параметр + * должен быть опциональным и должна быть возможность + * его отключить. В любом случае, кроме хакеров и + * разработчиков (при чём сомнительно, что хакерам + * это пригодиться), функция перезагрузки никому не + * нужна, поскольку загружать весь дополнительный + * контент снова (js,css) в готовой версии нет + * необходимости. + * + */ + //console.log(event.keyCode); + var lCurrentFile; + var lName; + /* если клавиши можно обрабатывать*/ + if(CloudCommander.keyBinded){ + /* если нажали таб: + * переносим курсор на + * правую панель, если + * мы были на левой и + * наоборот + */ + if(event.keyCode===9){ + console.log('Tab pressed'); + try{ + lCurrentFile=document.getElementsByClassName(CloudCommander.CURRENT_FILE)[0]; + }catch(error){console.log(error);} + } + /* навигация по таблице файлов*/ + /* если нажали клавишу вверх*/ + else if(event.keyCode===38){ + /* получаем выдленный файл*/ + lCurrentFile=document.getElementsByClassName(CloudCommander.CURRENT_FILE); + /* если ненайдены выделенные файлы - выходим*/ + if(lCurrentFile.length===0)return; + lCurrentFile=lCurrentFile[0]; + /* если это строка существет и + * если она не заголовок + * файловой таблицы + */ + if(lCurrentFile.previousSibling && + lCurrentFile.previousSibling.className!=='fm_header' ){ + /* убираем выделение с текущего элемента */ + lCurrentFile.className=''; + /* и выделяем предыдущую строку*/ + lCurrentFile.previousSibling.className=CloudCommander.CURRENT_FILE; + event.preventDefault(); + } + } + /* если нажали клавишу в низ*/ + else if(event.keyCode===40){ + /* получаем выдленный файл*/ + lCurrentFile=document.getElementsByClassName(CloudCommander.CURRENT_FILE); + /* если ненайдены выделенные файлы - выходим*/ + if(lCurrentFile.length===0)return; + lCurrentFile=lCurrentFile[0]; + /* если это не последняя строка */ + if(lCurrentFile.nextSibling){ + /* убираем с него выделение */ + lCurrentFile.className=''; + /* выделяем следующую строку*/ + lCurrentFile.nextSibling.className=CloudCommander.CURRENT_FILE; + event.preventDefault(); + } + } + /* если нажали клавишу page up или Home + * переходим к самому верхнему + * элементу + */ + else if(/*event.keyCode===33 ||*/ event.keyCode===36){ + lCurrentFile=document.getElementsByClassName(CloudCommander.CURRENT_FILE)[0]; + /* убираем выделение с текущего файла*/ + lCurrentFile.className=''; + /* получаем первый элемент*/ + lCurrentFile.parentElement.firstElementChild + /* пропускаем путь и заголовки столбиков*/ + .nextElementSibling.nextElementSibling + /* выделяем верхий файл */ + .className=CloudCommander.CURRENT_FILE; + } + /* если нажали клавишу page down или End + * выделяем последний элемент + */ + else if(/*event.keyCode===34 ||*/ event.keyCode===35){ + lCurrentFile=document.getElementsByClassName(CloudCommander.CURRENT_FILE)[0]; + /* снимаем выделение с текущего файла*/ + lCurrentFile.className=''; + /* выделяем самый нижний файл */ + lCurrentFile.parentElement.lastElementChild.className=CloudCommander.CURRENT_FILE; + } + /* если нажали Enter - открываем папку*/ + else if(event.keyCode===13){ + lCurrentFile=document.getElementsByClassName(CloudCommander.CURRENT_FILE); + /* если ненайдены выделенные файлы - выходим*/ + if(!lCurrentFile.length)return; + lCurrentFile=lCurrentFile[0]; + /* из него достаём спан с именем файла*/ + lName=lCurrentFile.getElementsByClassName('name'); + /* если нету (что вряд ли) - выходим*/ + if(!lName)return false; + /* достаём все ссылки*/ + var lATag=lName[0].getElementsByTagName('a'); + /* если нету - выходим */ + if(!lATag)return false; + /* получаем ссылку на каталог, + * что на уровень выше + */ + /* получаем имя каталога в котором находимся*/ + var lHref; + try{ + lHref=lCurrentFile.parentElement.getElementsByClassName('path')[0].textContent; + }catch(error){console.log('error');} + lHref=CloudFunc.removeLastSlash(lHref); + var lSubstr=lHref.substr(lHref,lHref.lastIndexOf('/')); + lHref=lHref.replace(lSubstr+'/',''); + + /* вызываем ajaxload привязанный через changelinks + * пробулем нажать на ссылку, если не получиться + * (opera, ie), вызываем событие onclick, + * которое пока не прописано у файлов + */ + + if(lCurrentFile.onclick)lCurrentFile.onclick(true); + else try{ + lATag[0].click(); + } + catch(error){ + console.log(error); + } + } + /* если нажали +r */ + else if(event.keyCode===82 && + event.ctrlKey){ + console.log('+r pressed'); + console.log('reloading page...'); + console.log('press +q to remove all key-handlers'); + + /* обновляем страницу, */ + /* Загружаем содержимое каталога + * при этом данные берём всегда из + * сервера, а не из кэша + * (обновляем кэш) + */ + /* Программно нажимаем на кнопку перезагрузки + * содержимого каталога + */ + var lRefreshIcon=document.getElementsByClassName(CloudFunc.REFRESHICON); + if(lRefreshIcon)lRefreshIcon=lRefreshIcon[0]; + if(lRefreshIcon){ + /* находим файл который сейчас выделен */ + lCurrentFile=document.getElementsByClassName(CloudCommander.CURRENT_FILE); + if(lCurrentFile.length>0)lCurrentFile=lCurrentFile[0]; + /* получаем название файла*/ + var lSelectedName=lCurrentFile.getElementsByTagName('a')[0].textContent; + /* если нашли элемент нажимаем него + * а если не можем - нажимаем на + * ссылку, на которую повешен eventHandler + * onclick + */ + if(lRefreshIcon.click)lRefreshIcon.parentElement.click(); + else lRefreshIcon.parentElement.onclick(); + + /* перебираем файлы левой панели + * в поисках подсвеченого файла + */ + var lLeft=document.getElementById('left'); + if(lLeft){ + /* перебираем все файлы в панели */ + var lLi=lLeft.getElementsByTagName('li'); + lCurrentFile.className=''; + /* начинаем с 2-ух, по скольку + * 0 - это путь + * 1 - это заголовок файловой таблицы + */ + for(var i=2;i+d чистим кэш */ + else if(event.keyCode===68 && + event.ctrlKey){ + console.log('+d pressed'); + console.log('clearing cache...'); + console.log('press +q to remove all key-handlers'); + + var lClearCache=document.getElementById('clear-cache'); + if(lClearCache && lClearCache.onclick)lClearCache.onclick(); + + event.preventDefault();//запрет на дальнейшее действие + } + /* если нажали +q + * убираем все обработчики + * нажатий клавиш + */ + else if(event.keyCode===81 && + event.altKey){ + //document.removeEventListener('keydown', key_event,false); + console.log('+q pressed'); + console.log('+r reload key-handerl - removed'); + console.log('+s clear cache key-handler - removed'); + console.log('press +s to to set them'); + + /* обработчик нажатий клавиш снят*/ + CloudCommander.keyBinded=false; + } + } + /* если нажали +s + * устанавливаем все обработчики + * нажатий клавиш + */ + else if(event.keyCode===83 && + event.altKey){ + /* + document.addEventListener('keydown', key_event,false); + */ + /* обрабатываем нажатия на клавиши*/ + CloudCommander.keyBinded=true; + + console.log('+s pressed'); + console.log('+r reload key-handerl - set'); + console.log('+s clear cache key-handler - set'); + console.log('press +q to remove them'); + } + + return false; + }; + /* добавляем обработчик клавишь */ + if(document.addEventListener) + document.addEventListener('keydown', key_event,false); + else document.onkeypress=key_event; + /* клавиши назначены*/ + CloudCommander.keyBinded=true; +}); \ No newline at end of file diff --git a/lib/cloudfunc.js b/lib/cloudfunc.js new file mode 100644 index 00000000..231f36dd --- /dev/null +++ b/lib/cloudfunc.js @@ -0,0 +1,504 @@ +"use strict"; +/* Модуль, содержащий функции, которые будут работать + * и на клиенте и на сервере + * + * Правила названий: + * varName - имя функции + * lVarName - имя локальной переменной + * pVarName - имя параметра + * fVarName - имя функции созданной внутри функции + * VARNAME - имя константы + * + * Типы переменных: + * varNameS - строка + * varNameN - число + * varNameO - обьект + * varNameM - массив + */ + +var CloudFunc={ + /* Путь с которым мы сейчас работаем */ + Path :'', + /* КОНСТАНТЫ (общие для клиента и сервера)*/ + /* название программы */ + NAME :'Cloud Commander', + /* если в ссылке будет эта строка - + * в браузере js отключен + */ + NOJS : '/no-js', + FS : '/c/f/s', + /* название css-класа кнопки обновления файловой структуры*/ + REFRESHICON : 'refresh-icon', + /* id панелей с файлами */ + LEFTPANEL : 'left', + RIGHTPANEL : 'right' + /* name of direcotory with libs */ +}; + +/* + * Функция убирает последний слеш, + * если он - последний символ строки + */ +CloudFunc.removeLastSlash = function(pPath){ + if(typeof pPath==='string') + return (pPath.lastIndexOf('/')===pPath.length-1)? + pPath.substr(pPath, pPath.length-1):pPath; + else return pPath; +}; +/* + * Функция меняет код символа пробела на пробел + * в переданной строке + * @pPath - строка + */ +CloudFunc.replaceSpaces = function(pPath){ + if(pPath.indexOf('%20')>0){ + do{ + pPath=pPath.replace('%20',' '); + }while(pPath.indexOf('%20')>0); + } + return pPath; +}; + +/* Функция возвращает заголовок веб страницы */ +CloudFunc.setTitle = function(){ + + return CloudFunc.Path===''?CloudFunc.NAME: + CloudFunc.Path + + ' - ' + + CloudFunc.NAME; +}; +/* Функция переводит права из цыфрового вида в символьный + * @pPerm_s - строка с правами доступа + * к файлу в 8-миричной системе + */ +CloudFunc.convertPermissionsToSymbolic= function(pPerm_s){ + /* + S_IRUSR 0000400 protection: readable by owner + S_IWUSR 0000200 writable by owner + S_IXUSR 0000100 executable by owner + S_IRGRP 0000040 readable by group + S_IWGRP 0000020 writable by group + S_IXGRP 0000010 executable by group + S_IROTH 0000004 readable by all + S_IWOTH 0000002 writable by all + S_IXOTH 0000001 executable by all + */ + if(pPerm_s===undefined) return; + + /* тип файла */ + var lType=pPerm_s.charAt(0); + + switch (lType-0) { + case 1: /* обычный файл */ + lType='-'; + break; + case 2: /* байт-ориентированное (символьное) устройство*/ + lType='c'; + break; + case 4: /* каталог */ + lType='d'; + break; + default: + lType='-'; + } + + /* оставляем последние 3 символа*/ + pPerm_s=pPerm_s.length>5?pPerm_s.substr(3):pPerm_s.substr(2); + + /* Рекомендации гугла советуют вместо string[3] + * использовать string.charAt(3) + */ +/* + http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml?showone=Standards_features#Standards_features + + Always preferred over non-standards featuresFor + maximum portability and compatibility, always + prefer standards features over non-standards + features (e.g., string.charAt(3) over string[3] + and element access with DOM functions instead + of using an application-specific shorthand). +*/ + /* Переводим в двоичную систему */ + var lOwner=(pPerm_s[0]-0).toString(2); + var lGroup=(pPerm_s[1]-0).toString(2); + var lAll =(pPerm_s[2]-0).toString(2); + /* + console.log(lOwner+' '+lGroup+' '+lAll); + */ + /* переводим в символьную систему*/ + var lPermissions=//lType+' '+ + (lOwner[0]-0>0?'r':'-')+ + (lOwner[1]-0>0?'w':'-')+ + (lOwner[2]-0>0?'x':'-')+ + ' ' + + (lGroup[0]-0>0?'r':'-')+ + (lGroup[1]-0>0?'w':'-')+ + (lGroup[2]-0>0?'x':'-')+ + ' ' + + (lAll[0]-0>0?'r':'-')+ + (lAll[1]-0>0?'w':'-')+ + (lAll[2]-0>0?'x':'-'); + /* + console.log(lPermissions); + */ + return lPermissions; +}; + +/* Функция конвертирует права доступа к файлам из символьного вида + * в цыфровой + */ +CloudFunc.convertPermissionsToNumberic= function(pPerm_s){ + /* если передана правильная строка, конвертированная + * функциец convertPermissionsToSymbolic + */ + if(!pPerm_s || pPerm_s.length!==11)return pPerm_s; + + var lOwner= (pPerm_s[0]==='r'?4:0) + + (pPerm_s[1]==='w'?2:0) + + (pPerm_s[2]==='x'?1:0); + var lGroup= (pPerm_s[4]==='r'?4:0) + + (pPerm_s[5]==='w'?2:0) + + (pPerm_s[6]==='x'?1:0); + var lAll = (pPerm_s[8]==='r'?4:0) + + (pPerm_s[9]==='w'?2:0) + + (pPerm_s[10]==='x'?1:0); + /* добавляем 2 цыфры до 5 */ + return '00'+lOwner+lGroup+lAll; +}; +/* Функция получает короткие размеры + * конвертируя байт в килобайты, мегабойты, + * гигайбайты и терабайты + * @pSize - размер в байтах + */ +CloudFunc.getShortedSize=function(pSize){ + /* if pSize=0 - return it */ + if(!pSize)return pSize; + + /* Константы размеров, что используются + * внутри функции + */ + var l1BMAX=1024; + var l1KBMAX=1048576; + var l1MBMAX=1073741824; + var l1GBMAX=1099511627776; + var l1TBMAX=1125899906842624; + + var lShorted; + + if(pSize2){ + if(folders[0].lastIndexOf('/')===folders[0].length) + LPrevDir=folders[1]; + else LPrevDir=folders[2]; + }else LPrevDir='/'; + */ + /* ################################### */ + + /* Формируем ссылки на каждый каталог в пути */ + var lHref=''; + var lHrefEnd=''; + + var lHtmlPath; + /* путь в ссылке, который говорит + * что js отключен + */ + var lNoJS_s=CloudFunc.NOJS; + var lFS_s=CloudFunc.FS; + /* корневой каталог */ + lHtmlPath=lHref+lFS_s+lNoJS_s+lTitle+'"/"'+_l+'/'+lHrefEnd; + for(i=folders.length-1;i>0;i--) + { + var lUrl=folders[i]; + var lShortName=lUrl.replace(lUrl.substr(lUrl,lUrl.lastIndexOf('/')+1),''); + if(i!==1) + { + lHtmlPath+=lHref+lFS_s+lNoJS_s+lUrl+lTitle+lUrl+_l+lShortName+lHrefEnd+'/'; + } + else + lHtmlPath+=lShortName+'/'; + } + /* *** */ + return lHtmlPath; +}; + +/* + * Функция ищет в имени файла расширение + * и если находит возвращает true + * @pName - получает имя файла + * @pExt - расширение + */ +CloudFunc.checkExtension=function(pName,pExt) +{ + /* если длина имени больше + * длинны расширения - + * имеет смысл продолжать + */ + if(pName.length>pExt.length){ + var lLength=pName.length; /* длина имени*/ + var lExtNum=pName.lastIndexOf(pExt);/* последнее вхождение расширения*/ + var lExtSub=lLength-lExtNum; /* длина расширения*/ + /* если pExt - расширение pName */ + if(lExtSub===pExt.length) + return true; + else + return false; + } + else return false; +}; + +/* + * Функция формирует заголовки столбиков + * @pFileTableTitles - массив названий столбиков + */ +CloudFunc._getFileTableHeader=function(pFileTableTitles) +{ + var lHeader='
  • '; + lHeader+=''; + for(var i=0;i'+ + lStr+ + ''; + } + lHeader+='
  • '; + + return lHeader; +}; + +/* + * Функция строит таблицу файлв из JSON-информации о файлах + * @pJSON - информация о файлах + * @pKeyBinded - если клавиши назначены, выделяем верхний файл + * [{path:'путь',size:'dir'}, + * {name:'имя',size:'размер',mode:'права доступа'}] + */ +CloudFunc.buildFromJSON=function(pJSON,pKeyBinded) +{ + var files; + /* + * если пропарсить стандартными + * функциями нельзя - + * пробуем eval, + */ + /* + * Если мы на клиенте и нет JSON - + * через eval парсим. + * Если-же мы на сервере, + * или на клиенте всё есть + * парсим стандарным методом + */ + + /* По скольку мы прописали заголовок application/json + * нет необходимости его конвертировать, + * но она есть, если мы вытягиваем данные из + * localStorage + */ + files=pJSON; + /* сохраняем путь каталога в котором мы сейчас находимся*/ + var lPath=files[0].path; + + /* сохраняем путь */ + CloudFunc.Path=lPath; + + /* + * Строим путь каталога в котором мы находимся + * со всеми подкаталогами + */ + var lHtmlPath=CloudFunc._getDirPath(lPath); + + /* Убираем последний слэш + * с пути для кнопки обновить страницу + * если он есть + */ + var lRefreshPath=CloudFunc.removeLastSlash(lPath); + + /* путь в ссылке, который говорит + * что js отключен + */ + var lNoJS_s=CloudFunc.NOJS; + var lFS_s=CloudFunc.FS; + + var lFileTable='
  • '+ + ''+ + ''+ + '' + + ''+ + ''+ + ''+lHtmlPath+''+ + '
  • '; + + var fileTableTitles=['name','size','owner','mode']; + lFileTable+=CloudFunc._getFileTableHeader(fileTableTitles); + /* Если мы не в корне */ + if(lPath!=='/'){ + /* ссылка на верхний каталог*/ + var lDotDot; + /* убираем последний слеш и каталог в котором мы сейчас находимся*/ + lDotDot=lPath.substr(lPath,lPath.lastIndexOf('/')); + lDotDot=lDotDot.substr(lDotDot,lDotDot.lastIndexOf('/')); + /* Если предыдущий каталог корневой */ + if(lDotDot==='')lDotDot='/'; + + /* Сохраняем путь к каталогу верхнего уровня*/ + lFileTable += '
  • '+ + '' + + '' + + '' + + ''+".." + + '' + + '<dir>'+ + '.' + + '' + + '
  • '; + } + var lLength=files.length; + + for(var i=1;i'; + lFileTable +=''; + lFileTable +='' + + '16? + ' title="'+files[i].name+'">' + + files[i].name.substr( + files[i].name,16)+ + '..':'>'+files[i].name) + + "" + + ''; + /* если папка - не выводим размер */ + lFileTable +='' + + (files[i].size==='dir'? + '<dir>': + /* если это файл - получаем + * короткий размер + */ + CloudFunc.getShortedSize( + files[i].size)); + lFileTable +='' + + '' + + (!files[i].uid?'root':files[i].uid) + + '' + + '' + + /* конвертируем названия разрешений + * из числового формата в буквенный + * при этом корневой каталог не трогаем + * по скольку в нём и так всё уже + * установлено еще на сервере + */ + (//lPath==='/'?files[i].mode: + CloudFunc.convertPermissionsToSymbolic(files[i].mode)) + + ''; + lFileTable +=''; + } + + /* если клавиши назначены и + * мы в корневом каталоге и + * верхний файл еще не выделен - + * выделяем верхний файл + */ + if(pKeyBinded && lPath==='/'&& + lFileTable.indexOf('
  • ')<0){ + lFileTable=lFileTable.replace('
  • ','
  • '); + } + + + + return lFileTable; +}; + +/* + * Если мы на стороне сервера - + * прописываем экспортируемые функции + */ +try{ + if(exports){ + /* экспортируемые функции */ + exports.checkExtension = CloudFunc.checkExtension; + exports.buildFromJSON = CloudFunc.buildFromJSON; + exports.replaceSpaces = CloudFunc.replaceSpaces; + exports.setTitle = CloudFunc.setTitle; + exports.convertPermissions = CloudFunc.convertPermissions; + exports.getUserUIDsAndNames = CloudFunc.getUserUIDsAndNames; + + /* константы*/ + exports.Name = CloudFunc.NAME; + exports.NOJS = CloudFunc.NOJS; + exports.FS =CloudFunc.FS; + + console.log('cloudfunc.js loaded...'); + } +}catch(err){ + /* если мы на клиенте */ +} \ No newline at end of file diff --git a/lib/server/minify.js b/lib/server/minify.js new file mode 100644 index 00000000..86571283 --- /dev/null +++ b/lib/server/minify.js @@ -0,0 +1,279 @@ +/* Модуль сжатия js-скриптов и css*/ + +/* функция сжимает js-скрипты + * и сохраняет их с именем .min.js + */ + +var fs = require('fs'); + +/* CONSTANTS */ +/* dir contains css-files */ +var CSSDIR = 'css/'; + +exports.jsScripts=function jsScripts(){ + 'use strict'; + + /* подключаем модуль uglify-js + * если его нет - дальнейшая + * работа функции не имеет смысла + */ + try{ + var jsp = require("uglify-js").parser; + var pro = require("uglify-js").uglify; + }catch(error){ + console.log('can\'n load uglify-js\n' + + 'to use js-minification you need to install uglify-js\n' + + 'npm install uglify-js\n' + + 'https://github.com/mishoo/UglifyJS'); + return false; + } + /* Константы */ + var CLIENT_JS='client.js'; + var CLOUDFUNC_JS='lib/cloudfunc.js'; + var CLIENT_KEYBINDING_JS='lib/client/keyBinding.js'; + + var dataReaded_f=function(pFileName, pData){ + console.log('file ' + pFileName + ' readed'); + + /*********************************/ + /* сжимаем код через uglify-js */ + var uglify_js=function(pDdata){ + var orig_code = pDdata.toString(); + var ast = jsp.parse(orig_code); // parse code and get the initial AST + ast = pro.ast_mangle(ast); // get a new AST with mangled names + ast = pro.ast_squeeze(ast); // get an AST with compression optimizations + var result_code = pro.gen_code(ast); // compressed code here + return result_code; + }; + /*********************************/ + var final_code=uglify_js(pData); + + var minFileName=pFileName.replace('.js','.min.js'); + /* если мы сжимаем client.js - + * меняем строку cloudfunc.js на + * cloudfunc.min.js и выводим сообщение + * + * меняем строку keyBinding.js на + * keyBinding.min.js + * если другой файл - ничего не деалем + */ + if(pFileName===CLIENT_JS) + console.log('file name of ' + + CLOUDFUNC_JS + + ' in ' + + CLIENT_JS + + ' changed. size:', + (final_code=final_code + .replace('cloudfunc.js','cloudfunc.min.js') + .replace('keyBinding.js','keyBinding.min.js')).length); + + /* записываем сжатый js-скрипт*/ + fs.writeFile(minFileName, final_code, fileWrited(minFileName)); + }; + console.log('reading file ' + CLIENT_JS+'...'); + fs.readFile(CLIENT_JS,fileReaded(CLIENT_JS,dataReaded_f)); + + console.log('reading file ' + CLOUDFUNC_JS+'...'); + fs.readFile(CLOUDFUNC_JS,fileReaded(CLOUDFUNC_JS,dataReaded_f)); + + console.log('reading file ' + CLIENT_KEYBINDING_JS+'...'); + fs.readFile(CLIENT_KEYBINDING_JS, fileReaded(CLIENT_KEYBINDING_JS,dataReaded_f)); + + + return true; +}; + +/* функция сжимает css-стили + * и сохраняет их с именем .min.css + * @pImgConvertToBase64_b - булевый признак, + * который отвечает за то, что быконвертировать + * картинки в base64 и поместить в выходной css файл + */ +exports.cssStyles=function cssStyles(pImgConvertToBase64_b){ + 'use strict'; + + /* connecting cleanCSS, + * if we can't find it - + * return false + */ + var cleanCSS; + try{ + cleanCSS = require('clean-css'); + }catch(error){ + console.log('can\'n load clean-css \n' + + 'to use css-minification you need to install clean-css \n' + + 'npm install clean-css\n' + + 'https://github.com/GoalSmashers/clean-css'); + return false; + } + + /* Константы */ + var STYLE_CSS = CSSDIR+'style.css'; + var RESET_CSS = CSSDIR+'reset.css'; + + var lAllStyle=''; + var lResetCssDone=false; + var lStyleCssDone=false; + var dataReaded_f=function(pFileName, pData){ + console.log('file ' + pFileName + ' readed'); + /*********************************/ + /* сжимаем код через clean-css */ + var clean_css=function(pData){ + /* Сохраняем весь стиль в одну переменную*/ + return cleanCSS.process(pData); + }; + /*********************************/ + var final_code=clean_css(pData); + + lAllStyle+=final_code; + + var minFileName=pFileName.replace('.css','.min.css'); + + if(pFileName===STYLE_CSS)lStyleCssDone=true; + if(pFileName===RESET_CSS)lResetCssDone=true; + /* if all files writed we + * save all minimized css + * to one file all.min.css + */ + if(lStyleCssDone && lResetCssDone){ + /* если включена конвертация картинок в base64 + * вызываем её + */ + if(pImgConvertToBase64_b) + base64_images(lAllStyle); + else + fs.writeFile(CSSDIR+'all.min.css', lAllStyle, fileWrited('all.min.css')); + } + /* в другом случае - записываем сжатый css файл*/ + else fs.writeFile(minFileName, final_code, fileWrited(minFileName)); + }; + + console.log('reading file ' + STYLE_CSS+'...'); + fs.readFile(STYLE_CSS,fileReaded(STYLE_CSS,dataReaded_f)); + + console.log('reading file ' + RESET_CSS+'...'); + fs.readFile(RESET_CSS,fileReaded(RESET_CSS,dataReaded_f)); + + return true; +}; + +/* функция сжимает css-стили + * и сохраняет их с именем .min.css + */ +exports.html=function(){ + 'use strict'; + + /* connecting cleanCSS, + * if we can't find it - + * return false + */ + var htmlMinifier; + try{ + htmlMinifier = require('html-minifier'); + }catch(error){ + console.log('can\'n load html-minifier \n' + + 'to use html-minification you need to install html-minifier\n' + + 'npm install html-minifier\n' + + 'https://github.com/kangax/html-minifier'); + return false; + } + + /* Константы */ + var INDEX_HTML='index.html'; + + var dataReaded_f=function(pFileName, pData){ + console.log('file ' + pFileName + ' readed'); + /*********************************/ + /* сжимаем код через clean-css */ + var html_minify=function(pData){ + /* Сохраняем весь стиль в одну переменную*/ + + var lOptions={ + removeComments: true, + removeCommentsFromCDATA: true, + removeCDATASectionsFromCDATA: true, + collapseWhitespace: true, + collapseBooleanAttributes: true, + removeAttributeQuotes: true, + removeRedundantAttributes: true, + useShortDoctype: true, + removeEmptyAttributes: true, + /* оставляем, поскольку у нас + * в элемент fm генерируеться + * таблица файлов + */ + removeEmptyElements: false, + removeOptionalTags: true, + removeScriptTypeAttributes: true, + removeStyleLinkTypeAttributes: true + }; + + + return htmlMinifier.minify(pData,lOptions); + }; + /*********************************/ + var final_code=html_minify(pData); + + var minFileName=pFileName.replace('.html','.min.html'); + + /* записываем сжатый html файл*/ + fs.writeFile(minFileName, final_code, fileWrited(minFileName)); + }; + + console.log('reading file ' + INDEX_HTML+'...'); + fs.readFile(INDEX_HTML,fileReaded(INDEX_HTML,dataReaded_f)); + + return true; +}; + +/* функция переводит картинки в base64 и записывает в css-файл*/ +function base64_images(pFileContent_s){ + 'use strict'; + var b64img; + try{ + b64img = require('css-b64-images'); + }catch(error){ + console.log('can\'n load clean-css \n' + + 'to use images to base64 convertation you need to install css-base64-images \n' + + 'npm install -g css-b64-images\n' + + 'https://github.com/Filirom1/css-base64-images'); + return false; + } + b64img.fromString(pFileContent_s, '.','', function(err, css){ + console.log('images converted to base64 and saved in css file'); + fs.writeFile(CSSDIR+'all.min.css', css, fileWrited('all.min.css')); + }); +} + +/* Функция создаёт асинхроную версию + * для чтения файла + * @pFileName - имя считываемого файла + */ +function fileReaded(pFileName,pCompressFunc){ + "use strict"; + return function(pError,pData){ + /* функция в которую мы попадаем, + * если данные считались + * + * если ошибка - показываем её + * иначе если переданная функция - + * функция запускаем её + */ + if(!pError) + if (pCompressFunc && typeof pCompressFunc==="function") + pCompressFunc(pFileName,pData.toString()); + else console.log(pError); + }; +} + +/* + * Функция вызываеться после записи файла + * и выводит ошибку или сообщает, + * что файл успешно записан + */ +function fileWrited(pFileName){ + "use strict"; + return function(error){ + console.log(error?error:('file '+pFileName+' writed...')); + }; +} \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 00000000..738a4580 --- /dev/null +++ b/package.json @@ -0,0 +1,7 @@ +{ + "name": "cloudcmd", + "version": "0.0.1-5", + "scripts":{"test":"sh test/test.sh","start": "server.js"}, + "engines": { "node": "0.6.x" }, + "subdomain": "cloudcmd" +} \ No newline at end of file diff --git a/server.js b/server.js new file mode 100644 index 00000000..9e704d81 --- /dev/null +++ b/server.js @@ -0,0 +1,684 @@ +"use strict"; + +/* Обьект содержащий все функции и переменные + * серверной части Cloud Commander'а + */ +var CloudServer={ + /* функция, которая генерирует заголовки + * файлов, отправляемые сервером клиенту + */ + generateHeaders :function(){}, + /* функция высылает + * данные клиенту + */ + sendResponse :function(){}, + /* Структура содержащая функции, + * и переменные, в которых + * говориться о поддерживаемых + * браузером технологиях + */ + BrowserSuport :{}, + /* Обьект для работы с кэшем */ + Cashe :{}, + /* Обьект через который + * выполняеться сжатие + * скриптов и стилей + */ + Minify :{}, + /* Асоциативный масив обьектов для + * работы с ответами сервера + * высылаемыми на запрос о файле и + * хранащий информацию в виде + * Responces[name]=responce; + */ + Responses :{}, + + /* ПЕРЕМЕННЫЕ */ + /* Поддержка браузером JS*/ + NoJS :true, + /* Поддержка gzip-сжатия + * браузером + */ + Gzip :undefined, + + /* КОНСТАНТЫ */ + /* index.html */ + INDEX :'index.html', + /* name of direcotory with libs */ + LIBDIR :'./lib', + LIBDIRSERVER :'./lib/server', + Port :31337, /* server port */ + IP :'127.0.0.1' +}; + +/* + * Обьект для работы с кэшем + * аналог клиентского обьекта + * с тем отличием, что в нём + * будут храниться серверные + * данные, такие как файлы + * отдаваемые клиенту + * (файлы проэкта по большому + * счёту, для ускорения + * первичной загрузки) + */ +CloudServer.Cache={ + _allowed :true, /* приватный переключатель возможности работы с кэшем */ + /* данные в которых храняться файлы + * в формате <поле> : <значение> + * _data[name]=pData; + * одному имени соответствуют + * одни данные + */ + _data :{}, + + /* функция говорит можно ли работать с кэшем */ + isAllowed :(function(){ + return CloudServer.Cache._allowed; + }), + /* функция устанавливает возможность работать с кэшем */ + setAllowed :(function(pAllowed){ + CloudServer.Cache._allowed=pAllowed; + }), + /* Если доступен кэш + * сохраняем в него данные + */ + set :(function(pName, pData){ + if(CloudServer.Cache._allowed && pName && pData){ + CloudServer.Cache._data[pName]=pData; + } + }), + /* Если доступен Cache принимаем из него данные*/ + get :(function(pName){ + if(CloudServer.Cache._allowed && pName){ + return CloudServer.Cache._data[pName]; + } + else return null; + }), + + /* Функция очищает кэш*/ + clear :(function(){ + if(CloudServer.Cache._allowed){ + CloudServer.Cache._data={}; + } + }) +}; + +/* Обьект для сжатия скриптов и стилей + * по умолчанию - сжимаються + */ +CloudServer.Minify={ + /* приватный переключатель минимизации */ + _allowed :{css:true,js:true,html:true, img: true}, + + /* функция разрешает или + * запрещает минимизировать + * css/js/html + * @pAllowed: - структура, в которой + * передаються параметры + * минификации, вида + * {js:true,css:true,html:false; img:true} + * img отвечает за перевод картинок в base64 + * и сохранение их в css-файл + */ + setAllowed :(function(pAllowed){ + if(pAllowed){ + this._allowed.css=pAllowed.css; + this._allowed.js=pAllowed.js; + this._allowed.html=pAllowed.html; + this._allowed.img=pAllowed.img; + } + }), + + /* + * Функция минимизирует css/js/html + * если установлены параметры минимизации + */ + doit :(function(){ + if(this._allowed.css || + this._allowed.js || + this._allowed.html){ + var lMinify = require(CloudServer.LIBDIRSERVER+'/minify'); + + this.done.js=this._allowed.js?lMinify.jsScripts():false; + this.done.html=this._allowed.html?lMinify.html():false; + this.done.css=this._allowed.css?lMinify.cssStyles(this._allowed.img):false; + } + }), + /* свойство показывающее случилась ли ошибка*/ + done:{js: false,css: false, html:false} +}; + + +var LeftDir='/'; +var RightDir=LeftDir; +/* модуль для работы с путями*/ +var Path = require('path'); + +var Fs = require('fs'); /* модуль для работы с файловой системой*/ + +var Zlib; +/* node v0.4 not contains zlib + */ +try{ + Zlib = require('zlib'); /* модуль для сжатия данных gzip-ом*/ +}catch(error){ + Zlib=undefined; + console.log('to use gzip-commpression' + + 'you should install zlib module\n' + + 'npm install zlib'); +} +var CloudFunc = require(CloudServer.LIBDIR + + (CloudServer.Minify.done.js?/* если стоит минификация*/ + '/cloudfunc.min':/* добавляем сжатый - иначе обычный */ + '/cloudfunc')); /* модуль с функциями */ +/* конструктор*/ +CloudServer.init=(function(){ + /* Determining server.js directory + * and chang current process directory + * (usually /) to it. + * argv[1] - is always script name + */ + var lServerDir = Path.dirname(process.argv[1]); + console.log('current dir: ' + process.cwd()); + console.log('server dir: ' + lServerDir); + process.chdir(lServerDir); + + var lConfig={ + "cache" : {"allowed" : true}, + "minification" : { + "js" : true, + "css" : true, + "html" : true, + "img" : true + } + }; + try{ + console.log('reading configureation file config.json...'); + lConfig=require('./config'); + console.log('config.json readed'); + }catch(pError){ + console.log('warning: configureation file config.json not found...\n' + + 'using default values...\n' + + JSON.stringify(lConfig)); + } + + /* Переменная в которой храниться кэш*/ + CloudServer.Cache.setAllowed(lConfig.cache.allowed); + /* Change default parameters of + * js/css/html minification + */ + CloudServer.Minify.setAllowed(lConfig.minification); + /* Если нужно минимизируем скрипты */ + CloudServer.Minify.doit(); +}); + + +/* создаём сервер на порту 31337 */ +CloudServer.start=function() +{ + CloudServer.init(); + + /* constant ports of deployng servers + var lCloudFoundryPort = process.env.VCAP_APP_PORT; + var lNodesterPort = process.env.app_port; + var lC9Port = process.env.PORT; + */ + CloudServer.Port = process.env.PORT || /* c9 */ + process.env.app_port || /* nodester */ + process.env.VCAP_APP_PORT || /* cloudfoundry */ + CloudServer.Port; + + CloudServer.IP = process.env.IP || /* c9 */ + CloudServer.IP; + + var http = require('http'); + http.createServer(CloudServer._controller).listen( + CloudServer.Port, + CloudServer.IP); + + console.log('Cloud Commander server running at http://' + + CloudServer.IP + + ':' + + CloudServer.Port); + /* + (!lC9Port? + (!lCloudFoundryPort? + (!lNodesterPort?31337:lNodesterPort) + :lCloudFoundryPort) + :lC9Port)); + */ +}; + + +/* Функция создаёт заголовки файлов + * в зависимости от расширения файла + * перед отправкой их клиенту + * @pName - имя файла + * @pGzip - данные сжаты gzip'ом + */ +CloudServer.generateHeaders = function(pName, pGzip){ + var lType=''; + /* высылаем заголовок в зависимости от типа файла */ + /* если расширение у файла css - + * загружаем стили + */ + if(CloudFunc.checkExtension(pName,'css')) + lType='text/css'; + /* загружаем js */ + else if(CloudFunc.checkExtension(pName,'js')) + lType='text/javascript'; + /* загружаем картинки*/ + else if(CloudFunc.checkExtension(pName,'png')) + lType='image/png'; + /* загружаем json*/ + else if(CloudFunc.checkExtension(pName,'json')) + lType='application/json'; + else if(CloudFunc.checkExtension(pName,'html')) + lType='text/html'; + else if(CloudFunc.checkExtension(pName,'appcache')) + lType='text/cache-manifest'; + /* если это неизвестный тип файла - + * высылаем его просто как текст + */ + else lType='text/plain'; + + return { + /* if type of file any, but img - + * then we shoud specify charset + */ + 'Content-Type': lType + (lType.indexOf('img')<0?'; charset=UTF-8':''), + 'cache-control': 'max-age='+(31337*21), + 'last-modified': new Date().toString(), + 'content-encoding': pGzip?'gzip':'', + /* https://developers.google.com/speed/docs/best-practices/caching?hl=ru#LeverageProxyCaching */ + 'Vary': 'Accept-Encoding' + }; +}; + +/* + * Главная функция, через которую проихсодит + * взаимодействие, обмен данными с клиентом + * @req - запрос клиента (Request) + * @res - ответ сервера (Response) + */ +CloudServer._controller=function(pReq, pRes) +{ + /* Читаем содержимое папки, + переданное в url + */ + var url = require("url"); + var pathname = url.parse(pReq.url).pathname; + console.log('pathname: '+pathname); + + /* получаем поддерживаемые браузером кодировки*/ + var lAcceptEncoding = pReq.headers['accept-encoding']; + /* запоминаем поддерживает ли браузер + * gzip-сжатие при каждом обращении к серверу + * и доступен ли нам модуль zlib + */ + if (lAcceptEncoding && + lAcceptEncoding.match(/\bgzip\b/) && + Zlib){ + CloudServer.Gzip=true; + }else + CloudServer.Gzip=false; + /* путь в ссылке, который говорит + * что js отключен + */ + var lNoJS_s=CloudFunc.NOJS; + var lFS_s=CloudFunc.FS; + + if(pathname!=='/favicon.ico') + { + console.log("request for " + pathname + " received..."); + var lName; + + /* если в пути нет информации ни о ФС, + * ни об отсутствии js, + * ни о том, что это корневой + * каталог - загружаем файлы проэкта + */ + if(pathname.indexOf(lFS_s)<0 && + pathname.indexOf(lNoJS_s)<0 && + pathname!=='/'){ + /* если имена файлов проекта - загружаем их*/ + /* убираем слеш и читаем файл с текущец директории*/ + //lName=Path.basename(pathname); + + /* добавляем текующий каталог к пути */ + lName='.'+pathname; + console.log('reading '+lName); + /* сохраняем указатель на responce и имя */ + CloudServer.Responses[lName]=pRes; + + /* Берём значение из кэша + * сжатый файл - если gzip-поддерживаеться браузером + * не сжатый - в обратном случае + */ + var lFileData=CloudServer.Cache.get(CloudServer.Gzip?(lName+'_gzip'):lName); + + var lReadFileFunc_f=CloudServer.getReadFileFunc(lName); + /* если там что-то есть передаём данные в функцию + * readFile + */ + if(lFileData){ + console.log('readed from cache'); + /* передаём данные с кэша, + * если gzip включен - сжатые + * в обратном случае - несжатые + */ + lReadFileFunc_f(undefined,lFileData,true); + } + else Fs.readFile(lName,lReadFileFunc_f); + + }else{/* если мы имеем дело с файловой системой*/ + /* если путь не начинаеться с no-js - значит + * js включен + */ + /* убираем пометку cloud, без которой c9.io + * не работает поскольку путь из двух слешей + * (/fs/no-js/) - очень короткий, нужно + * длиннее + */ + + if(pathname.indexOf(lNoJS_s)!==lFS_s.length && pathname!=='/'){ + CloudServer.NoJS=false; + }else pathname=pathname.replace(lNoJS_s,''); + + /* убираем индекс файловой системы */ + if(pathname.indexOf(lFS_s)===0){ + pathname=pathname.replace(lFS_s,''); + /* если посетитель только зашел на сайт + * no-js будет пустым, как и fs + */ + /* если в пути нету fs - посетитель только зашел на сайт + * загружаем его полностью. + */ + }else CloudServer.NoJS=true; + /* если в итоге путь пустой + * делаем его корневым + */ + if(pathname==='')pathname='/'; + + RightDir=pathname; + LeftDir=pathname; + + /* если встретиться пробел - + * меня код символа пробела на пробел + */ + + LeftDir=CloudFunc.replaceSpaces(LeftDir); + RightDir=CloudFunc.replaceSpaces(RightDir); + + /* Проверяем с папкой ли мы имеем дело */ + + /* читаем сновные данные о файле */ + var lStat; + try{ + lStat=Fs.statSync(LeftDir); + }catch(error){ + console.log(error); + CloudServer.Responses[LeftDir]=pRes; + CloudServer.sendResponse('OK',error.toString(),LeftDir); + } + /* если это каталог - + * читаем его содержимое + */ + try{ + /* если установлено сжатие + * меняем название html-файла и + * загружаем сжатый html-файл в дальнейшем + */ + CloudServer.INDEX=(CloudServer.Minify.done.html?'index.min.html':CloudServer.INDEX); + /* + * сохраним указатель на response + */ + CloudServer.Responses[CloudServer.INDEX]=pRes; + if(lStat.isDirectory()) + Fs.readdir(LeftDir,CloudServer._readDir); + /* отдаём файл */ + else if(lStat.isFile()){ + CloudServer.Responses[LeftDir]=pRes; + Fs.readFile(LeftDir,CloudServer.getReadFileFunc(LeftDir)); + console.log('reading file: '+LeftDir); + } + }catch(error){console.log(error);} + } + } +}; + +/* Функция читает ссылку или выводит информацию об ошибке*/ +CloudServer._readDir=function (pError, pFiles) +{ + if(!pError) + { + /* данные о файлах в формате JSON*/ + var lJSON=[]; + var lJSONFile={}; + /* Если мы не в корне добавляем слеш к будующим ссылкам */ + if(LeftDir!=='/') + { + RightDir+='/'; + LeftDir+='/'; + } + + pFiles=pFiles.sort(); + + lJSON[0]={path:LeftDir,size:'dir'}; + var fReturnFalse=function returnFalse(){return false;}; + for(var i=0;i','') + .replace('style.css','all.min.css') + :lIndex; + + lIndex = CloudServer.Minify.done.js?lIndex.replace('client.js','client.min.js'):lIndex; + + lIndex=lIndex.toString().replace('
    ','
    '+lList); + /* меняем title */ + lIndex=lIndex.replace('Cloud Commander', + ''+CloudFunc.setTitle()+''); + /* отображаем панель быстрых клавишь */ + lList=lIndex; + /* если браузер поддерживает gzip-сжатие*/ + lHeader=CloudServer.generateHeaders('text/html',CloudServer.Gzip); + }catch(error){console.log(error);} + }else{ + /* в обычном режиме(когда js включен + * высылаем json-структуру файлов + * с соответствующими заголовками + */ + lList=JSON.stringify(lJSON); + lHeader=CloudServer.generateHeaders('application/json',CloudServer.Gzip); + } + /* если браузер поддерживает gzip-сжатие - сжимаем данные*/ + if(CloudServer.Gzip){ + Zlib.gzip(lList,CloudServer.getGzipDataFunc(lHeader,CloudServer.INDEX)); + } + /* если не поддерживаеться - отсылаем данные без сжатия*/ + else + CloudServer.sendResponse(lHeader,lList,CloudServer.INDEX); + } + else + { + console.log(pError); + CloudServer.sendResponse('OK',pError.toString()); + } +}; + +/* Функция генерирует функция считывания файла + * таким образом, что бы у нас было + * имя считываемого файла + * @pName - полное имя файла + */ +CloudServer.getReadFileFunc = function(pName){ +/* + * @pError - ошибка + * @pData - данные + * @pFromFile - прочитано с файла bool + */ + var lReadFile=function(pError,pData,pFromCache_b){ + if (!pError){ + console.log('file ' + pName + ' readed'); + + /* берём из кэша данные файла + * если их нет в кэше - + * сохраняем + */ + if(!pFromCache_b && CloudServer.Cache.isAllowed) + CloudServer.Cache.set(pName,pData); + /* если кэш есть + * сохраняем его в переменную + * которая до этого будет пустая + * по скольку мы будем вызывать этот метод + * сами, ведь файл уже вычитан + */ + + var lHeader=CloudServer.generateHeaders(pName,CloudServer.Gzip); + /* если браузер поддерживает gzip-сжатие - сжимаем данные*/ + if(CloudServer.Gzip &&!pFromCache_b){ + /* сжимаем содержимое */ + Zlib.gzip(pData,CloudServer.getGzipDataFunc(lHeader,pName)); + } + else{ + /* высылаем несжатые данные */ + CloudServer.sendResponse(lHeader,pData,pName); + } + } + else + { + console.log(pError.path); + if(pError.path!=='passwd.json') + { + console.log(pError); + CloudServer.sendResponse('OK',pError.toString(),pName); + }else{ + CloudServer.sendResponse('OK','passwd.json'); + } + } + }; + return lReadFile; +}; + +/* Функция получает сжатые данные + * @pHeader - заголовок файла + */ +CloudServer.getGzipDataFunc=function(pHeader,pName){ + return function(error,pResult){ + if(!error){ + /* отправляем сжатые данные + * вместе с заголовком + */ + /* если установлена работа с кэшем + * сохраняем сжатые данные + */ + if(CloudServer.Cache.isAllowed){ + /* устанавливаем кєш */ + console.log(pName+' gziped'); + CloudServer.Cache.set(pName+'_gzip',pResult); + } + CloudServer.sendResponse(pHeader,pResult,pName); + } + else{ + console.log(error); + CloudServer.sendResponse(pHeader,error); + } + }; +}; +/* Функция высылает ответ серверу + * @pHead - заголовок + * @pData - данные + * @pName - имя отсылаемого файла + */ +CloudServer.sendResponse = function(pHead, pData,pName){ + /* если у нас есть указатель на responce + * для соответствующего файла - + * высылаем его + */ + var lResponse=CloudServer.Responses[pName]; + if(lResponse){ + lResponse.writeHead(200,pHead); + lResponse.end(pData); + console.log(pName+' sended'); + } +}; + +CloudServer.start(); \ No newline at end of file diff --git a/test/test.sh b/test/test.sh new file mode 100644 index 00000000..9ad8c6e2 --- /dev/null +++ b/test/test.sh @@ -0,0 +1,6 @@ +#!/bin/sh +npm i jshint -g +echo "jshint server.js client.js lib/cloudfunc.js" +jshint --config ./.jshintrc ./server.js ./client.js +echo "jshint ./lib/cloudfunc.js ./lib/server/minify.js ./lib/client/keyBinding.js" +jshint --config ./.jshintrc ./lib/cloudfunc.js ./lib/server/minify.js ./lib/client/keyBinding.js \ No newline at end of file