diff --git a/lib/client.js b/lib/client.js
index be8f9438..ebeaa32c 100644
--- a/lib/client.js
+++ b/lib/client.js
@@ -1,709 +1,709 @@
-/* Функция которая возвратит обьект CloudCommander
- * @CloudFunc - обьект содержащий общий функционал
- * клиентский и серверный
- */
-
-var Util, DOM, CloudFunc, $, KeyBinding, CloudCommander = (function(){
-'use strict';
-
-var Config, Modules;
-
-/* Клиентский обьект, содержащий функциональную часть*/
-var CloudCmd = {
- /* Конструктор CloudClient, который выполняет
- * весь функционал по инициализации
- */
- init : null, /* start initialization */
-
- KeyBinding : null, /* обьект обработки нажатий клавишь */
- KeysPanel : null, /* panel with key buttons f1-f8 */
- Editor : null, /* function loads and shows editor */
- Storage : null, /* function loads storage */
- Viewer : null, /* function loads and shows viewer */
- Terminal : null, /* function loads and shows terminal*/
- Menu : null, /* function loads and shows menu */
- GoogleAnalytics : null,
-
- _loadDir : null, /* Функция привязываеться ко всем
- * ссылкам и
- * загружает содержимое каталогов */
-
- /* ОБЬЕКТЫ */
-
- /* ПРИВАТНЫЕ ФУНКЦИИ */
- /* функция загружает json-данные о файловой системе */
- _ajaxLoad : null,
-
- /* Функция генерирует JSON из html-таблицы файлов */
- _getJSONfromFileTable : null,
-
- /* функция меняет ссыки на ajax-овые */
- _changeLinks : null,
-
- /* КОНСТАНТЫ*/
- LIBDIR : '/lib/',
- LIBDIRCLIENT : '/lib/client/',
- JSONDIR : '/json/',
- /* height of Cloud Commander
- * seting up in init()
- */
- HEIGHT : 0,
- MIN_ONE_PANEL_WIDTH : 1155,
- OLD_BROWSER : false,
-
- HOST : (function(){
- var lLocation = document.location;
- return lLocation.protocol + '//' + lLocation.host;
- })()
-};
-
-CloudCmd.GoogleAnalytics = function(){
- DOM.addOneTimeListener('mousemove', function(){
- var lUrl = CloudCmd.LIBDIRCLIENT + 'google_analytics.js';
-
- setTimeout(function(){
- DOM.jsload(lUrl);
- }, 5000);
- });
-};
-
-/**
- * Функция привязываеться ко всем ссылкам и
- * загружает содержимое каталогов
- *
- * @param pLink - ссылка
- * @param pNeedRefresh - необходимость обязательной загрузки данных с сервера
- */
-CloudCmd._loadDir = function(pLink, pNeedRefresh){
- return function(pEvent){
- /* показываем гиф загрузки возле пути папки сверху
- * ctrl+r нажата? */
-
- var lCurrentLink = DOM.getCurrentLink(),
- lHref = lCurrentLink.href,
- lParent = lCurrentLink.textContent,
- lLink = pLink || Util.removeStr(lHref, CloudCmd.HOST),
- lDir = DOM.getCurrentDir();
-
- if(pLink || lCurrentLink.target !== '_blank'){
- DOM.Images.showLoad(pNeedRefresh ? {top:true} : null);
-
- /* загружаем содержимое каталога */
- CloudCmd._ajaxLoad(lLink, { refresh: pNeedRefresh });
-
- /* если нажали на ссылку на верхний каталог*/
- if(lParent === '..' && lDir !== '/')
- CloudCmd._currentToParent(lDir);
- }
-
- DOM.preventDefault(pEvent);
- };
-};
-
-
-/**
- * Function edits file name
- *
- * @param pParent - parent element
- * @param pEvent
- */
-CloudCmd._editFileName = function(pParent){
- var lA = DOM.getCurrentLink(pParent);
-
- if (lA && lA.textContent !== '..'){
-
- lA.contentEditable = true;
- KeyBinding.unSet();
-
- /* setting event handler onclick
- * if user clicks somewhere keyBinded
- * backs
- */
- DOM.addOneTimeListener('click', function(){
- var lA = DOM.getCurrentLink(pParent);
- if (lA && lA.textContent !== '..')
- lA.contentEditable = false;
-
- KeyBinding.set();
- });
- }
-};
-
-
-/** функция устанавливает курсор на каталог
- * с которого мы пришли, если мы поднялись
- * в верх по файловой структуре
- * @param pDirName - имя каталога с которого мы пришли
- */
-CloudCmd._currentToParent = function(pDirName){
- /* убираем слэш с имени каталога */
- pDirName = Util.removeStr(pDirName, '/');
-
- /* опредиляем в какой мы панели: *
- * правой или левой */
- var lPanel = DOM.getPanel(),
- lRootDir = DOM.getById(pDirName + '(' + lPanel.id + ')');
-
- /* if found li element with ID directory name *
- * set it to current file */
- if(lRootDir){
- DOM.setCurrentFile(lRootDir);
- DOM.scrollIntoViewIfNeeded(lRootDir, true);
- }
-};
-
-/**
- * function load modules
- * @pParams = {name, path, func, dobefore, arg}
- */
-function loadModule(pParams){
- if(!pParams) return;
-
- var lName = pParams.name,
- lPath = pParams.path,
- lFunc = pParams.func,
- lDoBefore = pParams.dobefore;
-
- if( Util.isString(pParams) )
- lPath = pParams;
-
- if(lPath && !lName){
- lName = lPath[0].toUpperCase() + lPath.substring(1);
- lName = Util.removeStr(lName, '.js');
-
- var lSlash = lName.indexOf('/');
- if(lSlash > 0){
- var lAfterSlash = lName.substr(lSlash);
- lName = Util.removeStr(lName, lAfterSlash);
- }
- }
-
- if( !Util.isContainStr(lPath, '.js') )
- lPath += '.js';
-
- if(!CloudCmd[lName])
- CloudCmd[lName] = function(pArg){
- Util.exec(lDoBefore);
-
- return DOM.jsload(CloudCmd.LIBDIRCLIENT + lPath, lFunc ||
- function(){
- Util.exec(CloudCmd[lName].init, pArg);
- });
- };
-}
-/** Конструктор CloudClient, который
- * выполняет весь функционал по
- * инициализации
- */
-CloudCmd.init = function(){
- var lCallBack = function(){
- Util.loadOnLoad([
- initKeysPanel,
- initModules,
- baseInit
- ]);
- },
- lFunc = function(pCallBack){
- this.OLD_BROWSER = true;
- var lSrc = CloudCmd.LIBDIRCLIENT + 'ie.js';
-
- DOM.jqueryLoad(
- DOM.retJSLoad(lSrc, pCallBack)
- );
- };
-
- //Util.socketLoad();
-
- Util.ifExec(document.body.scrollIntoViewIfNeeded, lCallBack, lFunc);
-};
-
-function initModules(pCallBack){
- loadModule({
- /* привязываем клавиши к функциям */
- path : 'keyBinding.js',
- func : function(){
- KeyBinding = CloudCmd.KeyBinding;
- KeyBinding.init();
- }
- });
-
- CloudCmd.getModules(function(pModules){
- pModules = pModules || [];
-
- DOM.addListener('contextmenu', function(pEvent){
- CloudCmd.Menu.ENABLED || DOM.preventDefault(pEvent);
- }, document);
-
- var lStorage = 'storage',
- lShowLoadFunc = Util.retFunc( DOM.Images.showLoad ),
-
- lDoBefore = {
- 'editor/_codemirror' : lShowLoadFunc,
- 'viewer' : lShowLoadFunc
- },
-
- lLoad = function(pName, pPath, pDoBefore){
- loadModule({
- path : pPath,
- name : pName,
- dobefore : pDoBefore
- });
- };
-
- for(var i = 0, n = pModules.length; i < n ; i++){
- var lModule = pModules[i];
-
- if(Util.isString(lModule))
- lLoad(null, lModule, lDoBefore[lModule]);
- }
-
- var lStorageObj = Util.findObjByNameInArr( pModules, lStorage ),
- lMod = Util.getNamesFromObjArray( lStorageObj );
-
- for(i = 0, n = lMod.length; i < n; i++){
- var lName = lMod[i],
- lPath = lStorage + '/_' + lName.toLowerCase();
-
- lLoad(lName, lPath);
- }
-
-
- Util.exec(pCallBack);
-
- });
-}
-
-function initKeysPanel(pCallBack){
- var lKeysPanel = {},
-
- lFuncs =[
- null,
- null, /* f1 */
- null, /* f2 */
- CloudCmd.Viewer, /* f3 */
- CloudCmd.Editor, /* f4 */
- null, /* f5 */
- null, /* f6 */
- null, /* f7 */
- DOM.promptRemoveCurrent,/* f8 */
- ];
-
- for(var i = 1; i <= 8; i++){
- var lButton = 'f' + i,
- lEl = DOM.getById('f' + i);
-
- DOM.addClickListener(lFuncs[i], lEl);
- lKeysPanel[lButton] = lEl;
- }
-
- CloudCmd.KeysPanel = lKeysPanel;
- Util.exec(pCallBack);
-}
-
-function baseInit(pCallBack){
- if(window.applicationCache){
- var lFunc = applicationCache.onupdateready;
-
- applicationCache.onupdateready = function(){
- Util.log('app cacheed');
- location.reload();
-
- Util.exec(lFunc);
- };
- }
-
- /* загружаем общие функции для клиента и сервера */
- DOM.jsload(CloudCmd.LIBDIR + 'cloudfunc.js',function(){
- DOM.addListener("popstate", function(pEvent) {
- var lPath = pEvent.state;
-
- if(lPath)
- CloudCmd._ajaxLoad(lPath, {nohistory: true});
-
- return true;
- });
-
- /* берём из обьекта window общий с сервером функционал */
- CloudFunc = window.CloudFunc;
-
- /* меняем ссылки на ajax'овые */
- CloudCmd._changeLinks(CloudFunc.LEFTPANEL);
- CloudCmd._changeLinks(CloudFunc.RIGHTPANEL);
-
- /* устанавливаем переменную доступности кэша */
- DOM.Cache.isAllowed();
- /* Устанавливаем кэш корневого каталога */
- if( !DOM.Cache.get('/') )
- DOM.Cache.set('/', CloudCmd._getJSONfromFileTable());
- });
-
- /* устанавливаем размер высоты таблицы файлов
- * исходя из размеров разрешения экрана
- */
-
- /* выделяем строку с первым файлом */
- var lFmHeader = DOM.getByClass('fm-header');
- DOM.setCurrentFile(lFmHeader[0].nextSibling);
-
- /* показываем элементы, которые будут работать только, если есть js */
- var lFM = DOM.getById('fm');
- lFM.className='localstorage';
-
- /* формируем и округляем высоту экрана
- * при разрешениии 1024x1280:
- * 658 -> 700
- */
-
- var lHeight = window.screen.height;
- lHeight = lHeight - (lHeight/3).toFixed();
-
- lHeight = (lHeight / 100).toFixed() * 100;
-
- CloudCmd.HEIGHT = lHeight;
-
- DOM.cssSet({
- id:'cloudcmd',
- inner:
- '.panel{' +
- 'height:' + lHeight +'px;' +
- '}'
- });
-
- Util.exec(pCallBack);
- CloudCmd.KeyBinding();
-}
-
-CloudCmd.getConfig = function(pCallBack){
- Util.ifExec(Config, pCallBack, function(pCallBack){
- DOM.ajax({
- url : CloudCmd.JSONDIR + 'config.json',
- success : function(pConfig){
- Config = pConfig;
- Util.exec(pCallBack, pConfig);
- }
- });
- });
-};
-
-CloudCmd.getModules = function(pCallBack){
- Util.ifExec(Modules, pCallBack, function(pCallBack){
- DOM.ajax({
- url : CloudCmd.JSONDIR + 'modules.json',
- success : Util.retExec(pCallBack)
- });
- });
-};
-
-
-/* функция меняет ссыки на ajax-овые */
-CloudCmd._changeLinks = function(pPanelID){
- /* назначаем кнопку очистить кэш и показываем её */
- var lClearcache = DOM.getById('clear-cache');
- DOM.addClickListener(DOM.Cache.clear, lClearcache);
-
- /* меняем ссылки на ajax-запросы */
- var lPanel = DOM.getById(pPanelID),
- a = lPanel.getElementsByTagName('a'),
-
- /* номер ссылки иконки обновления страницы */
- lREFRESHICON = 0,
-
- /* путь в ссылке, который говорит
- * что js отключен
- */
- lNoJS_s = CloudFunc.NOJS,
-
- /* right mouse click function varible */
- lOnContextMenu_f = function(pEvent){
- var lReturn_b = true;
-
- KeyBinding.unSet();
-
- /* getting html element
- * currentTarget - DOM event
- * target - jquery event
- */
- var lTarget = pEvent.currentTarget || pEvent.target;
- DOM.setCurrentFile(lTarget);
-
- if(Util.isFunction(CloudCmd.Menu) ){
- CloudCmd.Menu({
- x: pEvent.x,
- y: pEvent.y
- });
-
- /* disabling browsers menu*/
- lReturn_b = false;
- DOM.Images.showLoad();
- }
-
- return lReturn_b;
- },
-
- /* drag and drop function varible
- * download file from browser to descktop
- * in Chrome (HTML5)
- */
- lOnDragStart_f = function(pEvent){
- var lElement = pEvent.target,
- lLink = lElement.href,
- lName = lElement.textContent,
- /* if it's directory - adding json extension */
- lType = lElement.parentElement.nextSibling;
-
- if(lType && lType.textContent === '
'){
- lLink = Util.removeStr(lLink, lNoJS_s);
- lName += '.json';
- }
-
- pEvent.dataTransfer.setData("DownloadURL",
- 'application/octet-stream' + ':' +
- lName + ':' +
- lLink);
- },
-
- lSetCurrentFile_f = function(pEvent){
- var pElement = pEvent.target,
- lTag = pElement.tagName;
-
- if(lTag !== 'LI')
- do{
- pElement = pElement.parentElement;
- lTag = pElement.tagName;
- }while(lTag !== 'LI');
-
- DOM.setCurrentFile(pElement);
- },
-
- lUrl = CloudCmd.HOST;
-
- var lLoadDirOnce = CloudCmd._loadDir();
- for(var i = 0, n = a.length; i < n ; i++){
- /* убираем адрес хоста*/
- var ai = a[i],
- link = ai.href.replace(lUrl, ''),
- lNEADREFRESH = i === lREFRESHICON,
- lLoadDir = CloudCmd._loadDir(link, lNEADREFRESH);
-
- /* ставим загрузку гифа на клик*/
- if(lNEADREFRESH)
- DOM.addClickListener( lLoadDir, ai.parentElement );
-
- /* устанавливаем обработчики на строку
- * на двойное нажатие на левую кнопку мышки */
- else{
- var lLi = ai.parentElement.parentElement;
-
- /* if we in path changing onclick events */
- if (lLi.className === 'path')
- DOM.addClickListener( lLoadDir, ai );
- else {
- DOM.addClickListener( DOM.preventDefault, lLi);
- DOM.addListener('mousedown', lSetCurrentFile_f, lLi);
- DOM.addListener('ondragstart', lOnDragStart_f, ai);
- /* if right button clicked menu will
- * loads and shows
- */
- DOM.addListener('contextmenu', lOnContextMenu_f, lLi);
-
- /* если ссылка на папку, а не файл */
- if(ai.target !== '_blank'){
- DOM.addListener('dblclick', lLoadDirOnce, lLi);
- DOM.addListener('touchend', lLoadDirOnce, lLi);
- }
-
- lLi.id = (ai.title ? ai.title : ai.textContent) +
- '(' + pPanelID + ')';
- }
- }
- }
-};
-
-/**
- * Функция загружает json-данные о Файловой Системе
- * через ajax-запрос.
- * @param path - каталог для чтения
- * @param pOptions
- * { refresh, nohistory } - необходимость обновить данные о каталоге
- */
-CloudCmd._ajaxLoad = function(pPath, pOptions){
- if(!pOptions)
- pOptions = {};
-
- /* Отображаем красивые пути */
- var lFSPath = decodeURI(pPath);
-
- lFSPath = Util.removeStr( lFSPath, CloudFunc.NOJS );
- var lCleanPath = Util.removeStr(lFSPath, CloudFunc.FS);
- Util.log ('reading dir: "' + lCleanPath + '";');
-
- if(!pOptions.nohistory)
- DOM.setHistory(pPath, null, pPath);
-
- DOM.setTitle( CloudFunc.getTitle(pPath) );
-
- /* если доступен localStorage и
- * в нём есть нужная нам директория -
- * читаем данные с него и
- * выходим
- * если стоит поле обязательной перезагрузки -
- * перезагружаемся
- */
-
- /* опредиляем в какой мы панели:
- * правой или левой
- */
- var lPanel = DOM.getPanel().id;
-
- if(!pOptions.refresh && lPanel){
- var lJSON = DOM.Cache.get(pPath);
-
- if (lJSON){
- /* переводим из текста в JSON */
- lJSON = Util.parseJSON(lJSON);
- CloudCmd._createFileTable(lPanel, lJSON);
- CloudCmd._changeLinks(lPanel);
-
- return;
- }
- }
-
- DOM.getCurrentFileContent({
- url : lFSPath,
- success : function(pData){
- CloudCmd._createFileTable(lPanel, pData);
- CloudCmd._changeLinks(lPanel);
-
- /* переводим таблицу файлов в строку, для *
- * сохранения в localStorage */
- var lJSON_s = Util.stringifyJSON(pData);
- Util.log(lJSON_s.length);
-
- /* если размер данных не очень бошьой *
- * сохраняем их в кэше */
- if(lJSON_s.length < 50000 )
- DOM.Cache.set(pPath, lJSON_s);
- }
- });
-};
-
-/**
- * Функция строит файловую таблицу
- * @param pEleme - родительский элемент
- * @param pJSON - данные о файлах
- */
-CloudCmd._createFileTable = function(pElem, pJSON){
- var lElem = DOM.getById(pElem),
- /* getting current element if was refresh */
- lPath = DOM.getByClass('path', lElem),
- lWasRefresh_b = lPath[0].textContent === pJSON[0].path,
- lCurrent;
-
- if(lWasRefresh_b)
- lCurrent = DOM.getCurrentFile();
-
- /* говорим построителю,
- * что бы он в нужный момент
- * выделил строку с первым файлом
- */
-
- /* очищаем панель */
- var i = lElem.childNodes.length;
- while(i--)
- lElem.removeChild(lElem.lastChild);
-
- /* заполняем панель новыми элементами */
- lElem.innerHTML = CloudFunc.buildFromJSON(pJSON, true);
-
- /* searching current file */
- if(lWasRefresh_b && lCurrent){
- for(i = 0; i < lElem.childNodes.length; i++)
- if(lElem.childNodes[i].textContent === lCurrent.textContent){
- lCurrent = lElem.childNodes[i];
- break;
- }
- DOM.setCurrentFile(lCurrent);
- }
-};
-
-/**
- * Функция генерирует JSON из html-таблицы файлов и
- * используеться при первом заходе в корень
- */
-CloudCmd._getJSONfromFileTable = function(){
- var lLeft = DOM.getById('left'),
- lPath = DOM.getByClass('path')[0].textContent,
-
- lFileTable = [{
- path:lPath,
- size:'dir'
- }],
-
- lLI = lLeft.getElementsByTagName('li'),
-
- j = 1; /* счётчик реальных файлов */
-
- /* счётчик элементов файлов в DOM */
- /* Если путь отличный от корневного
- * второй элемент li - это ссылка на верхний
- * каталог '..'
- */
-
- /* пропускам Path и Header*/
- for(var i = 2, n = lLI.length; i < n; i++){
- var lChildren = lLI[i].children,
- /* file attributes */
- lAttr = {};
-
- /* getting all elements to lAttr object */
- for(var l = 0; l < lChildren.length; l++)
- lAttr[lChildren[l].className] = lChildren[l];
-
- /* mini-icon */
- var lIsDir = lAttr['mini-icon directory'] ? true : false,
-
- lName = lAttr.name;
- if(lName)
- lName = DOM.getByTag('a', lName);
-
- /* if found link to folder
- * cheking is it a full name
- * or short
- */
- /* if short we got title
- * if full - getting textConent
- */
- if(lName.length)
- lName = lName[0];
-
- lName = lName.title || lName.textContent;
-
- /* если это папка - выводим слово dir вместо размера*/
- var lSize = lIsDir ? 'dir' : lAttr.size.textContent,
- lMode = lAttr.mode.textContent;
-
- /* переводим права доступа в цыфровой вид
- * для хранения в localStorage
- */
- lMode = CloudFunc.convertPermissionsToNumberic(lMode);
-
- lFileTable[ j++ ]={
- name: lName,
- size: lSize,
- mode: lMode
- };
- }
- return Util.stringifyJSON(lFileTable);
-};
-
-return CloudCmd;
-})();
-
-
-DOM.addOneTimeListener('load', function(){
- /* базовая инициализация*/
- CloudCommander.init();
-
- /* загружаем Google Analytics */
- CloudCommander.GoogleAnalytics();
-});
+/* Функция которая возвратит обьект CloudCommander
+ * @CloudFunc - обьект содержащий общий функционал
+ * клиентский и серверный
+ */
+
+var Util, DOM, CloudFunc, $, KeyBinding, CloudCommander = (function(Util, DOM){
+'use strict';
+
+var Config, Modules;
+
+/* Клиентский обьект, содержащий функциональную часть*/
+var CloudCmd = {
+ /* Конструктор CloudClient, который выполняет
+ * весь функционал по инициализации
+ */
+ init : null, /* start initialization */
+
+ KeyBinding : null, /* обьект обработки нажатий клавишь */
+ KeysPanel : null, /* panel with key buttons f1-f8 */
+ Editor : null, /* function loads and shows editor */
+ Storage : null, /* function loads storage */
+ Viewer : null, /* function loads and shows viewer */
+ Terminal : null, /* function loads and shows terminal*/
+ Menu : null, /* function loads and shows menu */
+ GoogleAnalytics : null,
+
+ _loadDir : null, /* Функция привязываеться ко всем
+ * ссылкам и
+ * загружает содержимое каталогов */
+
+ /* ОБЬЕКТЫ */
+
+ /* ПРИВАТНЫЕ ФУНКЦИИ */
+ /* функция загружает json-данные о файловой системе */
+ _ajaxLoad : null,
+
+ /* Функция генерирует JSON из html-таблицы файлов */
+ _getJSONfromFileTable : null,
+
+ /* функция меняет ссыки на ajax-овые */
+ _changeLinks : null,
+
+ /* КОНСТАНТЫ*/
+ LIBDIR : '/lib/',
+ LIBDIRCLIENT : '/lib/client/',
+ JSONDIR : '/json/',
+ /* height of Cloud Commander
+ * seting up in init()
+ */
+ HEIGHT : 0,
+ MIN_ONE_PANEL_WIDTH : 1155,
+ OLD_BROWSER : false,
+
+ HOST : (function(){
+ var lLocation = document.location;
+ return lLocation.protocol + '//' + lLocation.host;
+ })()
+};
+
+CloudCmd.GoogleAnalytics = function(){
+ DOM.addOneTimeListener('mousemove', function(){
+ var lUrl = CloudCmd.LIBDIRCLIENT + 'google_analytics.js';
+
+ setTimeout(function(){
+ DOM.jsload(lUrl);
+ }, 5000);
+ });
+};
+
+/**
+ * Функция привязываеться ко всем ссылкам и
+ * загружает содержимое каталогов
+ *
+ * @param pLink - ссылка
+ * @param pNeedRefresh - необходимость обязательной загрузки данных с сервера
+ */
+CloudCmd._loadDir = function(pLink, pNeedRefresh){
+ return function(pEvent){
+ /* показываем гиф загрузки возле пути папки сверху
+ * ctrl+r нажата? */
+
+ var lCurrentLink = DOM.getCurrentLink(),
+ lHref = lCurrentLink.href,
+ lParent = lCurrentLink.textContent,
+ lLink = pLink || Util.removeStr(lHref, CloudCmd.HOST),
+ lDir = DOM.getCurrentDir();
+
+ if(pLink || lCurrentLink.target !== '_blank'){
+ DOM.Images.showLoad(pNeedRefresh ? {top:true} : null);
+
+ /* загружаем содержимое каталога */
+ CloudCmd._ajaxLoad(lLink, { refresh: pNeedRefresh });
+
+ /* если нажали на ссылку на верхний каталог*/
+ if(lParent === '..' && lDir !== '/')
+ CloudCmd._currentToParent(lDir);
+ }
+
+ DOM.preventDefault(pEvent);
+ };
+};
+
+
+/**
+ * Function edits file name
+ *
+ * @param pParent - parent element
+ * @param pEvent
+ */
+CloudCmd._editFileName = function(pParent){
+ var lA = DOM.getCurrentLink(pParent);
+
+ if (lA && lA.textContent !== '..'){
+
+ lA.contentEditable = true;
+ KeyBinding.unSet();
+
+ /* setting event handler onclick
+ * if user clicks somewhere keyBinded
+ * backs
+ */
+ DOM.addOneTimeListener('click', function(){
+ var lA = DOM.getCurrentLink(pParent);
+ if (lA && lA.textContent !== '..')
+ lA.contentEditable = false;
+
+ KeyBinding.set();
+ });
+ }
+};
+
+
+/** функция устанавливает курсор на каталог
+ * с которого мы пришли, если мы поднялись
+ * в верх по файловой структуре
+ * @param pDirName - имя каталога с которого мы пришли
+ */
+CloudCmd._currentToParent = function(pDirName){
+ /* убираем слэш с имени каталога */
+ pDirName = Util.removeStr(pDirName, '/');
+
+ /* опредиляем в какой мы панели: *
+ * правой или левой */
+ var lPanel = DOM.getPanel(),
+ lRootDir = DOM.getById(pDirName + '(' + lPanel.id + ')');
+
+ /* if found li element with ID directory name *
+ * set it to current file */
+ if(lRootDir){
+ DOM.setCurrentFile(lRootDir);
+ DOM.scrollIntoViewIfNeeded(lRootDir, true);
+ }
+};
+
+/**
+ * function load modules
+ * @pParams = {name, path, func, dobefore, arg}
+ */
+function loadModule(pParams){
+ if(!pParams) return;
+
+ var lName = pParams.name,
+ lPath = pParams.path,
+ lFunc = pParams.func,
+ lDoBefore = pParams.dobefore;
+
+ if( Util.isString(pParams) )
+ lPath = pParams;
+
+ if(lPath && !lName){
+ lName = lPath[0].toUpperCase() + lPath.substring(1);
+ lName = Util.removeStr(lName, '.js');
+
+ var lSlash = lName.indexOf('/');
+ if(lSlash > 0){
+ var lAfterSlash = lName.substr(lSlash);
+ lName = Util.removeStr(lName, lAfterSlash);
+ }
+ }
+
+ if( !Util.isContainStr(lPath, '.js') )
+ lPath += '.js';
+
+ if(!CloudCmd[lName])
+ CloudCmd[lName] = function(pArg){
+ Util.exec(lDoBefore);
+
+ return DOM.jsload(CloudCmd.LIBDIRCLIENT + lPath, lFunc ||
+ function(){
+ Util.exec(CloudCmd[lName].init, pArg);
+ });
+ };
+}
+/** Конструктор CloudClient, который
+ * выполняет весь функционал по
+ * инициализации
+ */
+CloudCmd.init = function(){
+ var lCallBack = function(){
+ Util.loadOnLoad([
+ initKeysPanel,
+ initModules,
+ baseInit
+ ]);
+ },
+ lFunc = function(pCallBack){
+ this.OLD_BROWSER = true;
+ var lSrc = CloudCmd.LIBDIRCLIENT + 'ie.js';
+
+ DOM.jqueryLoad(
+ DOM.retJSLoad(lSrc, pCallBack)
+ );
+ };
+
+ //Util.socketLoad();
+
+ Util.ifExec(document.body.scrollIntoViewIfNeeded, lCallBack, lFunc);
+};
+
+function initModules(pCallBack){
+ loadModule({
+ /* привязываем клавиши к функциям */
+ path : 'keyBinding.js',
+ func : function(){
+ KeyBinding = CloudCmd.KeyBinding;
+ KeyBinding.init();
+ }
+ });
+
+ CloudCmd.getModules(function(pModules){
+ pModules = pModules || [];
+
+ DOM.addListener('contextmenu', function(pEvent){
+ CloudCmd.Menu.ENABLED || DOM.preventDefault(pEvent);
+ }, document);
+
+ var lStorage = 'storage',
+ lShowLoadFunc = Util.retFunc( DOM.Images.showLoad ),
+
+ lDoBefore = {
+ 'editor/_codemirror' : lShowLoadFunc,
+ 'viewer' : lShowLoadFunc
+ },
+
+ lLoad = function(pName, pPath, pDoBefore){
+ loadModule({
+ path : pPath,
+ name : pName,
+ dobefore : pDoBefore
+ });
+ };
+
+ for(var i = 0, n = pModules.length; i < n ; i++){
+ var lModule = pModules[i];
+
+ if(Util.isString(lModule))
+ lLoad(null, lModule, lDoBefore[lModule]);
+ }
+
+ var lStorageObj = Util.findObjByNameInArr( pModules, lStorage ),
+ lMod = Util.getNamesFromObjArray( lStorageObj );
+
+ for(i = 0, n = lMod.length; i < n; i++){
+ var lName = lMod[i],
+ lPath = lStorage + '/_' + lName.toLowerCase();
+
+ lLoad(lName, lPath);
+ }
+
+
+ Util.exec(pCallBack);
+
+ });
+}
+
+function initKeysPanel(pCallBack){
+ var lKeysPanel = {},
+
+ lFuncs =[
+ null,
+ null, /* f1 */
+ null, /* f2 */
+ CloudCmd.Viewer, /* f3 */
+ CloudCmd.Editor, /* f4 */
+ null, /* f5 */
+ null, /* f6 */
+ null, /* f7 */
+ DOM.promptRemoveCurrent,/* f8 */
+ ];
+
+ for(var i = 1; i <= 8; i++){
+ var lButton = 'f' + i,
+ lEl = DOM.getById('f' + i);
+
+ DOM.addClickListener(lFuncs[i], lEl);
+ lKeysPanel[lButton] = lEl;
+ }
+
+ CloudCmd.KeysPanel = lKeysPanel;
+ Util.exec(pCallBack);
+}
+
+function baseInit(pCallBack){
+ if(window.applicationCache){
+ var lFunc = applicationCache.onupdateready;
+
+ applicationCache.onupdateready = function(){
+ Util.log('app cacheed');
+ location.reload();
+
+ Util.exec(lFunc);
+ };
+ }
+
+ /* загружаем общие функции для клиента и сервера */
+ DOM.jsload(CloudCmd.LIBDIR + 'cloudfunc.js',function(){
+ DOM.addListener("popstate", function(pEvent) {
+ var lPath = pEvent.state;
+
+ if(lPath)
+ CloudCmd._ajaxLoad(lPath, {nohistory: true});
+
+ return true;
+ });
+
+ /* берём из обьекта window общий с сервером функционал */
+ CloudFunc = window.CloudFunc;
+
+ /* меняем ссылки на ajax'овые */
+ CloudCmd._changeLinks(CloudFunc.LEFTPANEL);
+ CloudCmd._changeLinks(CloudFunc.RIGHTPANEL);
+
+ /* устанавливаем переменную доступности кэша */
+ DOM.Cache.isAllowed();
+ /* Устанавливаем кэш корневого каталога */
+ if( !DOM.Cache.get('/') )
+ DOM.Cache.set('/', CloudCmd._getJSONfromFileTable());
+ });
+
+ /* устанавливаем размер высоты таблицы файлов
+ * исходя из размеров разрешения экрана
+ */
+
+ /* выделяем строку с первым файлом */
+ var lFmHeader = DOM.getByClass('fm-header');
+ DOM.setCurrentFile(lFmHeader[0].nextSibling);
+
+ /* показываем элементы, которые будут работать только, если есть js */
+ var lFM = DOM.getById('fm');
+ lFM.className='localstorage';
+
+ /* формируем и округляем высоту экрана
+ * при разрешениии 1024x1280:
+ * 658 -> 700
+ */
+
+ var lHeight = window.screen.height;
+ lHeight = lHeight - (lHeight/3).toFixed();
+
+ lHeight = (lHeight / 100).toFixed() * 100;
+
+ CloudCmd.HEIGHT = lHeight;
+
+ DOM.cssSet({
+ id:'cloudcmd',
+ inner:
+ '.panel{' +
+ 'height:' + lHeight +'px;' +
+ '}'
+ });
+
+ Util.exec(pCallBack);
+ CloudCmd.KeyBinding();
+}
+
+CloudCmd.getConfig = function(pCallBack){
+ Util.ifExec(Config, pCallBack, function(pCallBack){
+ DOM.ajax({
+ url : CloudCmd.JSONDIR + 'config.json',
+ success : function(pConfig){
+ Config = pConfig;
+ Util.exec(pCallBack, pConfig);
+ }
+ });
+ });
+};
+
+CloudCmd.getModules = function(pCallBack){
+ Util.ifExec(Modules, pCallBack, function(pCallBack){
+ DOM.ajax({
+ url : CloudCmd.JSONDIR + 'modules.json',
+ success : Util.retExec(pCallBack)
+ });
+ });
+};
+
+
+/* функция меняет ссыки на ajax-овые */
+CloudCmd._changeLinks = function(pPanelID){
+ /* назначаем кнопку очистить кэш и показываем её */
+ var lClearcache = DOM.getById('clear-cache');
+ DOM.addClickListener(DOM.Cache.clear, lClearcache);
+
+ /* меняем ссылки на ajax-запросы */
+ var lPanel = DOM.getById(pPanelID),
+ a = lPanel.getElementsByTagName('a'),
+
+ /* номер ссылки иконки обновления страницы */
+ lREFRESHICON = 0,
+
+ /* путь в ссылке, который говорит
+ * что js отключен
+ */
+ lNoJS_s = CloudFunc.NOJS,
+
+ /* right mouse click function varible */
+ lOnContextMenu_f = function(pEvent){
+ var lReturn_b = true;
+
+ KeyBinding.unSet();
+
+ /* getting html element
+ * currentTarget - DOM event
+ * target - jquery event
+ */
+ var lTarget = pEvent.currentTarget || pEvent.target;
+ DOM.setCurrentFile(lTarget);
+
+ if(Util.isFunction(CloudCmd.Menu) ){
+ CloudCmd.Menu({
+ x: pEvent.x,
+ y: pEvent.y
+ });
+
+ /* disabling browsers menu*/
+ lReturn_b = false;
+ DOM.Images.showLoad();
+ }
+
+ return lReturn_b;
+ },
+
+ /* drag and drop function varible
+ * download file from browser to descktop
+ * in Chrome (HTML5)
+ */
+ lOnDragStart_f = function(pEvent){
+ var lElement = pEvent.target,
+ lLink = lElement.href,
+ lName = lElement.textContent,
+ /* if it's directory - adding json extension */
+ lType = lElement.parentElement.nextSibling;
+
+ if(lType && lType.textContent === ''){
+ lLink = Util.removeStr(lLink, lNoJS_s);
+ lName += '.json';
+ }
+
+ pEvent.dataTransfer.setData("DownloadURL",
+ 'application/octet-stream' + ':' +
+ lName + ':' +
+ lLink);
+ },
+
+ lSetCurrentFile_f = function(pEvent){
+ var pElement = pEvent.target,
+ lTag = pElement.tagName;
+
+ if(lTag !== 'LI')
+ do{
+ pElement = pElement.parentElement;
+ lTag = pElement.tagName;
+ }while(lTag !== 'LI');
+
+ DOM.setCurrentFile(pElement);
+ },
+
+ lUrl = CloudCmd.HOST;
+
+ var lLoadDirOnce = CloudCmd._loadDir();
+ for(var i = 0, n = a.length; i < n ; i++){
+ /* убираем адрес хоста*/
+ var ai = a[i],
+ link = ai.href.replace(lUrl, ''),
+ lNEADREFRESH = i === lREFRESHICON,
+ lLoadDir = CloudCmd._loadDir(link, lNEADREFRESH);
+
+ /* ставим загрузку гифа на клик*/
+ if(lNEADREFRESH)
+ DOM.addClickListener( lLoadDir, ai.parentElement );
+
+ /* устанавливаем обработчики на строку
+ * на двойное нажатие на левую кнопку мышки */
+ else{
+ var lLi = ai.parentElement.parentElement;
+
+ /* if we in path changing onclick events */
+ if (lLi.className === 'path')
+ DOM.addClickListener( lLoadDir, ai );
+ else {
+ DOM.addClickListener( DOM.preventDefault, lLi);
+ DOM.addListener('mousedown', lSetCurrentFile_f, lLi);
+ DOM.addListener('ondragstart', lOnDragStart_f, ai);
+ /* if right button clicked menu will
+ * loads and shows
+ */
+ DOM.addListener('contextmenu', lOnContextMenu_f, lLi);
+
+ /* если ссылка на папку, а не файл */
+ if(ai.target !== '_blank'){
+ DOM.addListener('dblclick', lLoadDirOnce, lLi);
+ DOM.addListener('touchend', lLoadDirOnce, lLi);
+ }
+
+ lLi.id = (ai.title ? ai.title : ai.textContent) +
+ '(' + pPanelID + ')';
+ }
+ }
+ }
+};
+
+/**
+ * Функция загружает json-данные о Файловой Системе
+ * через ajax-запрос.
+ * @param path - каталог для чтения
+ * @param pOptions
+ * { refresh, nohistory } - необходимость обновить данные о каталоге
+ */
+CloudCmd._ajaxLoad = function(pPath, pOptions){
+ if(!pOptions)
+ pOptions = {};
+
+ /* Отображаем красивые пути */
+ var lFSPath = decodeURI(pPath);
+
+ lFSPath = Util.removeStr( lFSPath, CloudFunc.NOJS );
+ var lCleanPath = Util.removeStr(lFSPath, CloudFunc.FS);
+ Util.log ('reading dir: "' + lCleanPath + '";');
+
+ if(!pOptions.nohistory)
+ DOM.setHistory(pPath, null, pPath);
+
+ DOM.setTitle( CloudFunc.getTitle(pPath) );
+
+ /* если доступен localStorage и
+ * в нём есть нужная нам директория -
+ * читаем данные с него и
+ * выходим
+ * если стоит поле обязательной перезагрузки -
+ * перезагружаемся
+ */
+
+ /* опредиляем в какой мы панели:
+ * правой или левой
+ */
+ var lPanel = DOM.getPanel().id;
+
+ if(!pOptions.refresh && lPanel){
+ var lJSON = DOM.Cache.get(pPath);
+
+ if (lJSON){
+ /* переводим из текста в JSON */
+ lJSON = Util.parseJSON(lJSON);
+ CloudCmd._createFileTable(lPanel, lJSON);
+ CloudCmd._changeLinks(lPanel);
+
+ return;
+ }
+ }
+
+ DOM.getCurrentFileContent({
+ url : lFSPath,
+ success : function(pData){
+ CloudCmd._createFileTable(lPanel, pData);
+ CloudCmd._changeLinks(lPanel);
+
+ /* переводим таблицу файлов в строку, для *
+ * сохранения в localStorage */
+ var lJSON_s = Util.stringifyJSON(pData);
+ Util.log(lJSON_s.length);
+
+ /* если размер данных не очень бошьой *
+ * сохраняем их в кэше */
+ if(lJSON_s.length < 50000 )
+ DOM.Cache.set(pPath, lJSON_s);
+ }
+ });
+};
+
+/**
+ * Функция строит файловую таблицу
+ * @param pEleme - родительский элемент
+ * @param pJSON - данные о файлах
+ */
+CloudCmd._createFileTable = function(pElem, pJSON){
+ var lElem = DOM.getById(pElem),
+ /* getting current element if was refresh */
+ lPath = DOM.getByClass('path', lElem),
+ lWasRefresh_b = lPath[0].textContent === pJSON[0].path,
+ lCurrent;
+
+ if(lWasRefresh_b)
+ lCurrent = DOM.getCurrentFile();
+
+ /* говорим построителю,
+ * что бы он в нужный момент
+ * выделил строку с первым файлом
+ */
+
+ /* очищаем панель */
+ var i = lElem.childNodes.length;
+ while(i--)
+ lElem.removeChild(lElem.lastChild);
+
+ /* заполняем панель новыми элементами */
+ lElem.innerHTML = CloudFunc.buildFromJSON(pJSON, true);
+
+ /* searching current file */
+ if(lWasRefresh_b && lCurrent){
+ for(i = 0; i < lElem.childNodes.length; i++)
+ if(lElem.childNodes[i].textContent === lCurrent.textContent){
+ lCurrent = lElem.childNodes[i];
+ break;
+ }
+ DOM.setCurrentFile(lCurrent);
+ }
+};
+
+/**
+ * Функция генерирует JSON из html-таблицы файлов и
+ * используеться при первом заходе в корень
+ */
+CloudCmd._getJSONfromFileTable = function(){
+ var lLeft = DOM.getById('left'),
+ lPath = DOM.getByClass('path')[0].textContent,
+
+ lFileTable = [{
+ path:lPath,
+ size:'dir'
+ }],
+
+ lLI = lLeft.getElementsByTagName('li'),
+
+ j = 1; /* счётчик реальных файлов */
+
+ /* счётчик элементов файлов в DOM */
+ /* Если путь отличный от корневного
+ * второй элемент li - это ссылка на верхний
+ * каталог '..'
+ */
+
+ /* пропускам Path и Header*/
+ for(var i = 2, n = lLI.length; i < n; i++){
+ var lChildren = lLI[i].children,
+ /* file attributes */
+ lAttr = {};
+
+ /* getting all elements to lAttr object */
+ for(var l = 0; l < lChildren.length; l++)
+ lAttr[lChildren[l].className] = lChildren[l];
+
+ /* mini-icon */
+ var lIsDir = lAttr['mini-icon directory'] ? true : false,
+
+ lName = lAttr.name;
+ if(lName)
+ lName = DOM.getByTag('a', lName);
+
+ /* if found link to folder
+ * cheking is it a full name
+ * or short
+ */
+ /* if short we got title
+ * if full - getting textConent
+ */
+ if(lName.length)
+ lName = lName[0];
+
+ lName = lName.title || lName.textContent;
+
+ /* если это папка - выводим слово dir вместо размера*/
+ var lSize = lIsDir ? 'dir' : lAttr.size.textContent,
+ lMode = lAttr.mode.textContent;
+
+ /* переводим права доступа в цыфровой вид
+ * для хранения в localStorage
+ */
+ lMode = CloudFunc.convertPermissionsToNumberic(lMode);
+
+ lFileTable[ j++ ]={
+ name: lName,
+ size: lSize,
+ mode: lMode
+ };
+ }
+ return Util.stringifyJSON(lFileTable);
+};
+
+return CloudCmd;
+})(Util, DOM);
+
+
+DOM.addOneTimeListener('load', function(){
+ /* базовая инициализация*/
+ CloudCommander.init();
+
+ /* загружаем Google Analytics */
+ CloudCommander.GoogleAnalytics();
+});
diff --git a/lib/server/main.js b/lib/server/main.js
index 4d0b1242..f385596d 100644
--- a/lib/server/main.js
+++ b/lib/server/main.js
@@ -1,229 +1,224 @@
-(function(){
- 'strict mode';
-
- /* Global var accessible from any loaded module */
- global.cloudcmd = {};
-
- var DIR,
- LIBDIR,
- SRVDIR,
- JSONDIR,
- Util,
-
- SLASH,
- ISWIN32,
- ext,
- path,
- fs,
- zlib,
-
- OK = 200,
- FILE_NOT_FOUND = 404;
-
- /* Native Modules*/
- exports.crypto = require('crypto'),
- exports.child_process = require('child_process'),
- exports.fs = fs = require('fs'),
- exports.http = require('http'),
- exports.https = require('https'),
- exports.path = path = require('path'),
- exports.url = require('url'),
- exports.querystring = require('querystring'),
-
- /* Constants */
- /* current dir + 2 levels up */
- exports.WIN32 = ISWIN32 = isWin32();
- exports.SLASH = SLASH = ISWIN32 ? '\\' : '/',
-
- exports.SRVDIR = SRVDIR = __dirname + SLASH,
- exports.LIBDIR = LIBDIR = path.normalize(SRVDIR + '../'),
- exports.DIR = DIR = path.normalize(LIBDIR + '../'),
- exports.HTMLDIR = DIR + 'html/',
- exports.JSONDIR = JSONDIR = DIR + 'json/',
-
- /* Functions */
- exports.require = mrequire,
- exports.librequire = librequire,
- exports.srvrequire = srvrequire,
- exports.rootrequire = rootrequire,
- exports.generateHeaders = generateHeaders,
- exports.sendFile = sendFile,
-
- /* compitability with old versions of node */
- exports.fs.exists = exports.fs.exists || exports.path.exists;
-
- /* Needed Modules */
- exports.util = Util = require(LIBDIR + 'util'),
-
- exports.zlib = zlib = mrequire('zlib'),
-
- /* Main Information */
- exports.config = jsonrequire('config');
- exports.modules = jsonrequire('modules');
- exports.ext = ext = jsonrequire('ext');
- exports.mainpackage = rootrequire('package');
-
-
- /*
- * Any of loaded below modules could work with global var so
- * it should be initialized first. Becouse of almost any of
- * moudles do not depends on each other all needed information
- * for all modules is initialized hear.
- */
- global.cloudcmd.main = exports;
-
- exports.VOLUMES = getVolumes(),
-
- /* Additional Modules */
- exports.socket = srvrequire('socket'),
- exports.auth = srvrequire('auth').auth,
- exports.appcache = srvrequire('appcache'),
- exports.cache = srvrequire('cache').Cache,
- exports.cloudfunc = librequire('cloudfunc'),
- exports.rest = srvrequire('rest').api,
- exports.update = srvrequire('update'),
- exports.ischanged = srvrequire('ischanged');
- exports.commander = srvrequire('commander');
- exports.minify = srvrequire('minify').Minify;
- /*
- * second initializing after all modules load, so global var is
- * totally filled of all information that should know all modules
- */
- global.cloudcmd.main = exports;
- /**
- * function do safe require of needed module
- * @param {Strin} pSrc
- */
- function mrequire(pSrc){
- var lModule,
- lError = Util.tryCatchLog(function(){
- lModule = require(pSrc);
- });
-
- if(lError)
- console.log(lError);
-
- return lModule;
- }
-
- function rootrequire(pSrc){ return mrequire(DIR + pSrc); }
-
- function librequire(pSrc){ return mrequire(LIBDIR + pSrc); }
-
- function srvrequire(pSrc){ return mrequire(SRVDIR + pSrc); }
-
- function jsonrequire(pSrc){ return mrequire(JSONDIR + pSrc);}
-
- /**
- * function check is current platform is win32
- */
- function isWin32(){ return process.platform === 'win32'; }
-
- /**
- * get volumes if win32 or get nothing if nix
- */
- function getVolumes(){
- var lRet = ISWIN32 ? [] : '/';
-
- if(ISWIN32)
- srvrequire('win').getVolumes(function(pVolumes){
- console.log(pVolumes);
- exports.VOLUMES = pVolumes;
- });
-
- return lRet;
- }
-
- /**
- * Функция создаёт заголовки файлов
- * в зависимости от расширения файла
- * перед отправкой их клиенту
- * @param pName - имя файла
- * @param pGzip - данные сжаты gzip'ом
- */
- function generateHeaders(pName, pGzip, pQuery){
- var lRet,
- lType = '',
- lContentEncoding = '',
- lCacheControl = 0,
-
- lExt = Util.getExtension(pName);
-
- if( Util.strCmp(lExt, '.appcache') )
- lCacheControl = 1;
-
- lType = ext[lExt] || 'text/plain';
-
- if( !Util.isContainStr(lType, 'img') )
- lContentEncoding = '; charset=UTF-8';
-
- if(Util.strCmp(pQuery, 'download') )
- lType = 'application/octet-stream';
-
-
- if(!lCacheControl)
- lCacheControl = 31337 * 21;
-
- lRet = {
- /* if type of file any, but img -
- * then we shoud specify charset
- */
- 'Content-Type': lType + lContentEncoding,
- 'cache-control': 'max-age=' + lCacheControl,
- 'last-modified': new Date().toString(),
- /* https://developers.google.com/speed/docs/best-practices
- /caching?hl=ru#LeverageProxyCaching */
- 'Vary': 'Accept-Encoding'
- };
-
- if(pGzip)
- lRet['content-encoding'] = 'gzip';
-
- return lRet;
- }
-
- /**
- * send file to client thru pipe
- * and gzip it if client support
- *
- * @param pName - имя файла
- * @param pGzip - данные сжаты gzip'ом
- */
- function sendFile(pParams){
- var lRet,
- lName, lReq, lRes;
-
- if(pParams){
- lName = pParams.name,
- lReq = pParams.request,
- lRes = pParams.response;
- }
-
- if(lName && lRes && lReq){
- var lEnc = lReq.headers['accept-encoding'] || '',
- lGzip = lEnc.match(/\bgzip\b/),
-
- lReadStream = fs.createReadStream(lName, {
- 'bufferSize': 4 * 1024
- });
-
- lReadStream.on('error', function(pError){
- lRes.writeHead(FILE_NOT_FOUND, 'OK');
- lRes.end(String(pError));
- });
-
- lRes.writeHead(OK, generateHeaders(lName, lGzip) );
-
- if (lGzip)
- lReadStream = lReadStream.pipe( zlib.createGzip() );
-
- lReadStream.pipe(lRes);
-
- lRet = true;
- }
-
- return lRet;
- }
-
-
-})();
+(function(){
+ 'strict mode';
+
+ /* Global var accessible from any loaded module */
+ global.cloudcmd = {};
+
+ var DIR, LIBDIR, SRVDIR, JSONDIR,
+ Util,
+
+ SLASH,
+ ISWIN32,
+ ext,
+ path, fs, zlib,
+
+ OK = 200,
+ FILE_NOT_FOUND = 404;
+
+ /* Native Modules*/
+ exports.crypto = require('crypto'),
+ exports.child_process = require('child_process'),
+ exports.fs = fs = require('fs'),
+ exports.http = require('http'),
+ exports.https = require('https'),
+ exports.path = path = require('path'),
+ exports.url = require('url'),
+ exports.querystring = require('querystring'),
+
+ /* Constants */
+ /* current dir + 2 levels up */
+ exports.WIN32 = ISWIN32 = isWin32();
+ exports.SLASH = SLASH = ISWIN32 ? '\\' : '/',
+
+ exports.SRVDIR = SRVDIR = __dirname + SLASH,
+ exports.LIBDIR = LIBDIR = path.normalize(SRVDIR + '../'),
+ exports.DIR = DIR = path.normalize(LIBDIR + '../'),
+ exports.HTMLDIR = DIR + 'html' + SLASH,
+ exports.JSONDIR = JSONDIR = DIR + 'json' + SLASH,
+
+ /* Functions */
+ exports.require = mrequire,
+ exports.librequire = librequire,
+ exports.srvrequire = srvrequire,
+ exports.rootrequire = rootrequire,
+ exports.generateHeaders = generateHeaders,
+ exports.sendFile = sendFile,
+
+ /* compitability with old versions of node */
+ exports.fs.exists = exports.fs.exists || exports.path.exists;
+
+ /* Needed Modules */
+ exports.util = Util = require(LIBDIR + 'util'),
+
+ exports.zlib = zlib = mrequire('zlib'),
+
+ /* Main Information */
+ exports.config = jsonrequire('config');
+ exports.modules = jsonrequire('modules');
+ exports.ext = ext = jsonrequire('ext');
+ exports.mainpackage = rootrequire('package');
+
+
+ /*
+ * Any of loaded below modules could work with global var so
+ * it should be initialized first. Becouse of almost any of
+ * moudles do not depends on each other all needed information
+ * for all modules is initialized hear.
+ */
+ global.cloudcmd.main = exports;
+
+ exports.VOLUMES = getVolumes(),
+
+ /* Additional Modules */
+ exports.socket = srvrequire('socket'),
+ exports.auth = srvrequire('auth').auth,
+ exports.appcache = srvrequire('appcache'),
+ exports.cache = srvrequire('cache').Cache,
+ exports.cloudfunc = librequire('cloudfunc'),
+ exports.rest = srvrequire('rest').api,
+ exports.update = srvrequire('update'),
+ exports.ischanged = srvrequire('ischanged');
+ exports.commander = srvrequire('commander');
+ exports.minify = srvrequire('minify').Minify;
+ /*
+ * second initializing after all modules load, so global var is
+ * totally filled of all information that should know all modules
+ */
+ global.cloudcmd.main = exports;
+ /**
+ * function do safe require of needed module
+ * @param {Strin} pSrc
+ */
+ function mrequire(pSrc){
+ var lModule,
+ lError = Util.tryCatchLog(function(){
+ lModule = require(pSrc);
+ });
+
+ if(lError)
+ console.log(lError);
+
+ return lModule;
+ }
+
+ function rootrequire(pSrc){ return mrequire(DIR + pSrc); }
+
+ function librequire(pSrc){ return mrequire(LIBDIR + pSrc); }
+
+ function srvrequire(pSrc){ return mrequire(SRVDIR + pSrc); }
+
+ function jsonrequire(pSrc){ return mrequire(JSONDIR + pSrc);}
+
+ /**
+ * function check is current platform is win32
+ */
+ function isWin32(){ return process.platform === 'win32'; }
+
+ /**
+ * get volumes if win32 or get nothing if nix
+ */
+ function getVolumes(){
+ var lRet = ISWIN32 ? [] : '/';
+
+ if(ISWIN32)
+ srvrequire('win').getVolumes(function(pVolumes){
+ console.log(pVolumes);
+ exports.VOLUMES = pVolumes;
+ });
+
+ return lRet;
+ }
+
+ /**
+ * Функция создаёт заголовки файлов
+ * в зависимости от расширения файла
+ * перед отправкой их клиенту
+ * @param pName - имя файла
+ * @param pGzip - данные сжаты gzip'ом
+ */
+ function generateHeaders(pName, pGzip, pQuery){
+ var lRet,
+ lType = '',
+ lContentEncoding = '',
+ lCacheControl = 0,
+
+ lExt = Util.getExtension(pName);
+
+ if( Util.strCmp(lExt, '.appcache') )
+ lCacheControl = 1;
+
+ lType = ext[lExt] || 'text/plain';
+
+ if( !Util.isContainStr(lType, 'img') )
+ lContentEncoding = '; charset=UTF-8';
+
+ if(Util.strCmp(pQuery, 'download') )
+ lType = 'application/octet-stream';
+
+
+ if(!lCacheControl)
+ lCacheControl = 31337 * 21;
+
+ lRet = {
+ /* if type of file any, but img -
+ * then we shoud specify charset
+ */
+ 'Content-Type': lType + lContentEncoding,
+ 'cache-control': 'max-age=' + lCacheControl,
+ 'last-modified': new Date().toString(),
+ /* https://developers.google.com/speed/docs/best-practices
+ /caching?hl=ru#LeverageProxyCaching */
+ 'Vary': 'Accept-Encoding'
+ };
+
+ if(pGzip)
+ lRet['content-encoding'] = 'gzip';
+
+ return lRet;
+ }
+
+ /**
+ * send file to client thru pipe
+ * and gzip it if client support
+ *
+ * @param pName - имя файла
+ * @param pGzip - данные сжаты gzip'ом
+ */
+ function sendFile(pParams){
+ var lRet,
+ lName, lReq, lRes;
+
+ if(pParams){
+ lName = pParams.name,
+ lReq = pParams.request,
+ lRes = pParams.response;
+ }
+
+ if(lName && lRes && lReq){
+ var lEnc = lReq.headers['accept-encoding'] || '',
+ lGzip = lEnc.match(/\bgzip\b/),
+
+ lReadStream = fs.createReadStream(lName, {
+ 'bufferSize': 4 * 1024
+ });
+
+ lReadStream.on('error', function(pError){
+ lRes.writeHead(FILE_NOT_FOUND, 'OK');
+ lRes.end(String(pError));
+ });
+
+ lRes.writeHead(OK, generateHeaders(lName, lGzip) );
+
+ if (lGzip)
+ lReadStream = lReadStream.pipe( zlib.createGzip() );
+
+ lReadStream.pipe(lRes);
+
+ lRet = true;
+ }
+
+ return lRet;
+ }
+
+
+})();