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; + } + + +})();