mirror of
https://github.com/coderaiser/cloudcmd.git
synced 2026-01-23 10:45:47 +00:00
clean
This commit is contained in:
parent
4609529c1b
commit
177f54b654
8 changed files with 0 additions and 2625 deletions
|
|
@ -1,2 +0,0 @@
|
|||
Cloud-Commander
|
||||
===============
|
||||
978
client.js
978
client.js
|
|
@ -1,978 +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('<script src="jquery.min.js"><\/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'
|
||||
};
|
||||
|
||||
/*
|
||||
* Обьект для работы с кэшем
|
||||
* в него будут включены функции для
|
||||
* работы с 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(){
|
||||
var key_event=function(event){
|
||||
/*
|
||||
* Делаем допущение что перезагружать Cloud Commander
|
||||
* посетителям не придёться, в любом случае, параметр
|
||||
* должен быть опциональным и должна быть возможность
|
||||
* его отключить. В любом случае, кроме хакеров и
|
||||
* разработчиков (при чём сомнительно, что хакерам
|
||||
* это пригодиться), функция перезагрузки никому не
|
||||
* нужна, поскольку загружать весь дополнительный
|
||||
* контент снова (js,css) в готовой версии нет
|
||||
* необходимости.
|
||||
*
|
||||
*/
|
||||
//console.log(event.keyCode);
|
||||
var lCurrentFile;
|
||||
/* если клавиши можно обрабатывать*/
|
||||
if(CloudClient.keyBinded){
|
||||
/* если нажали таб:
|
||||
* переносим курсор на
|
||||
* правую панель, если
|
||||
* мы были на левой и
|
||||
* наоборот
|
||||
*/
|
||||
if(event.keyCode===9){
|
||||
console.log('Tab pressed');
|
||||
try{
|
||||
lCurrentFile=document.getElementsByClassName(CloudClient.CURRENT_FILE)[0];
|
||||
}catch(error){console.log(error);}
|
||||
}
|
||||
/* навигация по таблице файлов*/
|
||||
/* если нажали клавишу вверх*/
|
||||
else if(event.keyCode===38){
|
||||
/* получаем выдленный файл*/
|
||||
lCurrentFile=document.getElementsByClassName(CloudClient.CURRENT_FILE);
|
||||
/* если ненайдены выделенные файлы - выходим*/
|
||||
if(lCurrentFile.length===0)return;
|
||||
lCurrentFile=lCurrentFile[0];
|
||||
/* если это строка существет и
|
||||
* если она не заголовок
|
||||
* файловой таблицы
|
||||
*/
|
||||
if(lCurrentFile.previousSibling &&
|
||||
lCurrentFile.previousSibling.className!=='fm_header' ){
|
||||
/* убираем выделение с текущего элемента */
|
||||
lCurrentFile.className='';
|
||||
/* и выделяем предыдущую строку*/
|
||||
lCurrentFile.previousSibling.className=CloudClient.CURRENT_FILE;
|
||||
event.preventDefault();
|
||||
}
|
||||
}
|
||||
/* если нажали клавишу в низ*/
|
||||
else if(event.keyCode===40){
|
||||
/* получаем выдленный файл*/
|
||||
lCurrentFile=document.getElementsByClassName(CloudClient.CURRENT_FILE);
|
||||
/* если ненайдены выделенные файлы - выходим*/
|
||||
if(lCurrentFile.length===0)return;
|
||||
lCurrentFile=lCurrentFile[0];
|
||||
/* если это не последняя строка */
|
||||
if(lCurrentFile.nextSibling){
|
||||
/* убираем с него выделение */
|
||||
lCurrentFile.className='';
|
||||
/* выделяем следующую строку*/
|
||||
lCurrentFile.nextSibling.className=CloudClient.CURRENT_FILE;
|
||||
event.preventDefault();
|
||||
}
|
||||
}
|
||||
/* если нажали клавишу page up или Home
|
||||
* переходим к самому верхнему
|
||||
* элементу
|
||||
*/
|
||||
else if(/*event.keyCode===33 ||*/ event.keyCode===36){
|
||||
lCurrentFile=document.getElementsByClassName(CloudClient.CURRENT_FILE)[0];
|
||||
/* убираем выделение с текущего файла*/
|
||||
lCurrentFile.className='';
|
||||
/* получаем первый элемент*/
|
||||
lCurrentFile.parentElement.firstElementChild
|
||||
/* пропускаем путь и заголовки столбиков*/
|
||||
.nextElementSibling.nextElementSibling
|
||||
/* выделяем верхий файл */
|
||||
.className=CloudClient.CURRENT_FILE;
|
||||
}
|
||||
/* если нажали клавишу page down или End
|
||||
* выделяем последний элемент
|
||||
*/
|
||||
else if(/*event.keyCode===34 ||*/ event.keyCode===35){
|
||||
lCurrentFile=document.getElementsByClassName(CloudClient.CURRENT_FILE)[0];
|
||||
/* снимаем выделение с текущего файла*/
|
||||
lCurrentFile.className='';
|
||||
/* выделяем самый нижний файл */
|
||||
lCurrentFile.parentElement.lastElementChild.className=CloudClient.CURRENT_FILE;
|
||||
}
|
||||
/* если нажали Enter - открываем папку*/
|
||||
else if(event.keyCode===13){
|
||||
lCurrentFile=document.getElementsByClassName(CloudClient.CURRENT_FILE);
|
||||
/* если ненайдены выделенные файлы - выходим*/
|
||||
if(!lCurrentFile.length)return;
|
||||
lCurrentFile=lCurrentFile[0];
|
||||
/* из него достаём спан с именем файла*/
|
||||
var 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);
|
||||
}
|
||||
}
|
||||
/* если нажали <ctr>+r */
|
||||
else if(event.keyCode===82 &&
|
||||
event.ctrlKey){
|
||||
console.log('<ctrl>+r pressed');
|
||||
console.log('reloading page...');
|
||||
console.log('press <alt>+q to remove all key-handlers');
|
||||
|
||||
/* обновляем страницу, */
|
||||
/* Загружаем содержимое каталога
|
||||
* при этом данные берём всегда из
|
||||
* сервера, а не из кэша
|
||||
* (обновляем кэш)
|
||||
*/
|
||||
/* Программно нажимаем на кнопку перезагрузки
|
||||
* содержимого каталога
|
||||
*/
|
||||
var lRefreshIcon=document.getElementsByClassName(CloudFunc.REFRESHICON);
|
||||
if(lRefreshIcon)lRefreshIcon=lRefreshIcon[0];
|
||||
if(lRefreshIcon){
|
||||
/* находим файл который сейчас выделен */
|
||||
lCurrentFile=document.getElementsByClassName(CloudClient.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<lLi.length;i++){
|
||||
var lName=lLi[i].getElementsByTagName('a')[0].innerText;
|
||||
if(lSelectedName.length===lName.length &&
|
||||
!lSelectedName.indexOf(lName)){
|
||||
lLi[i].className=CloudClient.CURRENT_FILE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
event.preventDefault();//запрет на дальнейшее действие
|
||||
}
|
||||
}
|
||||
/* если нажали <ctrl>+d чистим кэш */
|
||||
else if(event.keyCode===68 &&
|
||||
event.ctrlKey){
|
||||
console.log('<ctrl>+d pressed');
|
||||
console.log('clearing cache...');
|
||||
console.log('press <alt>+q to remove all key-handlers');
|
||||
|
||||
var lClearCache=document.getElementById('clear-cache');
|
||||
if(lClearCache && lClearCache.onclick)lClearCache.onclick();
|
||||
|
||||
event.preventDefault();//запрет на дальнейшее действие
|
||||
}
|
||||
/* если нажали <alt>+q
|
||||
* убираем все обработчики
|
||||
* нажатий клавиш
|
||||
*/
|
||||
else if(event.keyCode===81 &&
|
||||
event.altKey){
|
||||
//document.removeEventListener('keydown', key_event,false);
|
||||
console.log('<alt>+q pressed');
|
||||
console.log('<ctrl>+r reload key-handerl - removed');
|
||||
console.log('<ctrl>+s clear cache key-handler - removed');
|
||||
console.log('press <alt>+s to to set them');
|
||||
|
||||
/* обработчик нажатий клавиш снят*/
|
||||
CloudClient.keyBinded=false;
|
||||
}
|
||||
}
|
||||
/* если нажали <alt>+s
|
||||
* устанавливаем все обработчики
|
||||
* нажатий клавиш
|
||||
*/
|
||||
else if(event.keyCode===83 &&
|
||||
event.altKey){
|
||||
/*
|
||||
document.addEventListener('keydown', key_event,false);
|
||||
*/
|
||||
/* обрабатываем нажатия на клавиши*/
|
||||
CloudClient.keyBinded=true;
|
||||
|
||||
console.log('<alt>+s pressed');
|
||||
console.log('<ctrl>+r reload key-handerl - set');
|
||||
console.log('<ctrl>+s clear cache key-handler - set');
|
||||
console.log('press <alt>+q to remove them');
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
/* добавляем обработчик клавишь */
|
||||
if(document.addEventListener)
|
||||
document.addEventListener('keydown', key_event,false);
|
||||
else document.onkeypress=key_event;
|
||||
/* клавиши назначены*/
|
||||
CloudClient.keyBinded=true;
|
||||
});
|
||||
|
||||
|
||||
/*
|
||||
* Функция привязываеться ко всем ссылкам и
|
||||
* загружает содержимое каталогов
|
||||
*/
|
||||
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){
|
||||
/* если <ctrl>+<r>
|
||||
* кнопка обновления
|
||||
*/
|
||||
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);
|
||||
|
||||
/* получаем все элементы выделенной папки*/
|
||||
/* при этом, если мы нажали обновить
|
||||
* или <Ctrl>+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;
|
||||
|
||||
/*
|
||||
console.log('Error. Can\'t find current file.'+
|
||||
' (CloudClient._setCurrent)');
|
||||
*/
|
||||
/* если мы попали сюда с энтера*/
|
||||
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;i<lLi.length;i++){
|
||||
var lA=lLi[i].getElementsByTagName('a');
|
||||
if(lA.length && lA[0].innerText===pDirName){
|
||||
/* если уже выделен какой-то файл, снимаем
|
||||
* выделение
|
||||
*/
|
||||
lCurrentFile=lPanel.getElementsByClassName(CloudClient.CURRENT_FILE);
|
||||
if(lCurrentFile.length>0)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;
|
||||
window.jQuery || CloudClient.jsload('jquery.min.js',
|
||||
function(){
|
||||
$=window.jQuery;
|
||||
});
|
||||
});
|
||||
|
||||
/* загружаем общие функции для клиента и сервера*/
|
||||
CloudClient.jsload('/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','');
|
||||
|
||||
//var lLeft=document.getElementById('left');
|
||||
//lLeft.style.cssText='width:50%';
|
||||
CloudClient.cssSet({id:'show_2panels',
|
||||
element:document.head,
|
||||
inner:'#left{width:50%;}'
|
||||
});
|
||||
});
|
||||
|
||||
/* функция меняет ссыки на 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<a.length;i++)
|
||||
{
|
||||
//if(i===2){/*ставим рамку на первый с верху файл*/
|
||||
// a[i].parentElement.parentElement.className='current-file';
|
||||
// }
|
||||
/* если ссылка на папку, а не файл */
|
||||
if(a[i].target!='_blank')
|
||||
{
|
||||
/* убираем адрес хоста*/
|
||||
var link='/'+a[i].href.replace(document.location.href,'');
|
||||
/* убираем значения, которые говорят,
|
||||
* об отсутствии js
|
||||
*/
|
||||
|
||||
if(link.indexOf(lNoJS_s)===lFS_s.length){
|
||||
link=link.replace(lNoJS_s,'');
|
||||
}
|
||||
/* ставим загрузку гифа на клик*/
|
||||
if(i===lREFRESHICON)
|
||||
a[i].onclick=CloudClient._loadDir(link,true);
|
||||
/* если мы попали на кнопку обновления структуры каталогов */
|
||||
/*
|
||||
if(a[i].className && a[i].className===CloudFunc.REFRESHICON)
|
||||
*/
|
||||
/* устанавливаем обработчики на строку на одинарное и
|
||||
* двойное нажатие на левую кнопку мышки
|
||||
*/
|
||||
else{
|
||||
try{
|
||||
a[i].parentElement.parentElement.onclick=CloudClient._setCurrent();
|
||||
a[i].parentElement.parentElement.ondblclick=CloudClient._loadDir(link);
|
||||
}catch(error){console.log(error);}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Функция загружает json-данные о Файловой Системе
|
||||
* через ajax-запрос.
|
||||
* @path - каталог для чтения
|
||||
* @pNeedRefresh - необходимость обновить данные о каталоге
|
||||
*/
|
||||
CloudClient._ajaxLoad=function(path, pNeedRefresh)
|
||||
{
|
||||
/* Отображаем красивые пути */
|
||||
var lPath=path;
|
||||
var lFS_s=CloudFunc.FS;
|
||||
if(lPath.indexOf(lFS_s)===0){
|
||||
lPath=lPath.replace(lFS_s,'');
|
||||
if(lPath==='')lPath='/';
|
||||
}
|
||||
console.log ('reading dir: "'+lPath+'";');
|
||||
|
||||
/* если доступен localStorage и
|
||||
* в нём есть нужная нам директория -
|
||||
* читаем данные с него и
|
||||
* выходим
|
||||
* если стоит поле обязательной перезагрузки -
|
||||
* перезагружаемся
|
||||
*/
|
||||
|
||||
/* опредиляем в какой мы панели:
|
||||
* правой или левой
|
||||
*/
|
||||
var lPanel;
|
||||
try{
|
||||
lPanel=document.getElementsByClassName(CloudClient.CURRENT_FILE)[0].parentElement.id;
|
||||
}catch(error){console.log("Current file not found\n"+error);}
|
||||
|
||||
if(pNeedRefresh===undefined && lPanel){
|
||||
var lJSON=CloudClient.Cache.get(lPath);
|
||||
if (lJSON!==null){
|
||||
/* переводим из текста в JSON */
|
||||
if(window && !window.JSON){
|
||||
try{
|
||||
lJSON=eval('('+lJSON+')');
|
||||
}catch(err){
|
||||
console.log(err);
|
||||
}
|
||||
}else lJSON=JSON.parse(lJSON);
|
||||
CloudClient._createFileTable(lPanel,lJSON);
|
||||
CloudClient._changeLinks(lPanel);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* ######################## */
|
||||
try{
|
||||
$.ajax({
|
||||
url: path,
|
||||
error: function(jqXHR, textStatus, errorThrown){
|
||||
console.log(textStatus+' : '+errorThrown);
|
||||
var lLoading=document.getElementById('loading-image');
|
||||
ErrorImage.className='icon error';
|
||||
ErrorImage.title=errorThrown;
|
||||
lLoading.parentElement.appendChild(ErrorImage);
|
||||
lLoading.className='hidden';
|
||||
//document.getElementsByClassName('path')[0].appendChild(ErrorImage);
|
||||
|
||||
},
|
||||
success:function(data, textStatus, jqXHR){
|
||||
/* если такой папки (или файла) нет
|
||||
* прячем загрузку и показываем ошибку
|
||||
*/
|
||||
/* для совместимости с firefox меняем data
|
||||
* на jqXHR, он воспринимает data к Document
|
||||
* когда возвращаеться ошибка, о том, что
|
||||
* нет файла или нет доступа
|
||||
*/
|
||||
|
||||
var lLoading;
|
||||
if(!jqXHR.responseText.indexOf('Error:')){
|
||||
/* если файла не существует*/
|
||||
if(!jqXHR.responseText.indexOf('Error: ENOENT, ')){
|
||||
ErrorImage.title=jqXHR.responseText.replace('Error: ENOENT, n','N');
|
||||
}
|
||||
/* если не хватает прав для чтения файла*/
|
||||
else if(!jqXHR.responseText.indexOf('Error: EACCES,')){
|
||||
ErrorImage.title=jqXHR.responseText.replace('Error: EACCES, p','P');
|
||||
}
|
||||
ErrorImage.className='icon error';
|
||||
lLoading=document.getElementById('loading-image');
|
||||
lLoading.parentElement.appendChild(ErrorImage);
|
||||
lLoading.className='hidden';
|
||||
|
||||
return;
|
||||
}
|
||||
CloudClient._createFileTable(lPanel,data);
|
||||
CloudClient._changeLinks(lPanel);
|
||||
|
||||
/* Сохраняем структуру каталогов в localStorage,
|
||||
* если он поддерживаеться браузером
|
||||
*/
|
||||
/* переводим таблицу файлов в строку, для
|
||||
* сохранения в localStorage
|
||||
*/
|
||||
var lJSON_s=JSON.stringify(data);
|
||||
console.log(lJSON_s.length);
|
||||
|
||||
/* если размер данных не очень бошьой
|
||||
* сохраняем их в кэше
|
||||
*/
|
||||
if(lJSON_s.length<50000)
|
||||
CloudClient.Cache.set(lPath,lJSON_s);
|
||||
}
|
||||
});
|
||||
}catch(err){console.log(err);}
|
||||
};
|
||||
|
||||
/*
|
||||
* Функция строит файловую таблицу
|
||||
* @pEleme - родительский элемент
|
||||
* @pJSON - данные о файлах
|
||||
*/
|
||||
CloudClient._createFileTable = function(pElem,pJSON)
|
||||
{
|
||||
var lElem=document.getElementById(pElem);
|
||||
/* говорим построителю,
|
||||
* что бы он в нужный момент
|
||||
* выделил строку с первым файлом
|
||||
*/
|
||||
|
||||
/* очищаем панель */
|
||||
var i = lElem.childNodes.length;
|
||||
while(i--){
|
||||
lElem.removeChild(lElem.lastChild);
|
||||
}
|
||||
/* заполняем панель новыми элементами */
|
||||
|
||||
lElem.innerHTML=CloudFunc.buildFromJSON(pJSON,true);
|
||||
};
|
||||
|
||||
/*
|
||||
* Функция создаёт элемент и
|
||||
* загружает файл с src.
|
||||
* @pName - название тэга
|
||||
* @pSrc - путь к файлу
|
||||
* @pFunc - функци
|
||||
* @pStyle - стиль
|
||||
* @pId - id
|
||||
* @pElement - элемент, дочерним которо будет этот
|
||||
*/
|
||||
CloudClient._anyload = function(pName,pSrc,pFunc,pStyle,pId,pElement)
|
||||
{
|
||||
//если скрипт еще не загружен
|
||||
/* убираем путь к файлу, оставляя только название файла */
|
||||
var lID;
|
||||
if(pId===undefined){
|
||||
lID=pSrc.replace(pSrc.substr(pSrc,pSrc.lastIndexOf('/')+1),'');
|
||||
/* убираем точку*/
|
||||
lID=lID.replace('.','_');
|
||||
}else lID=pId;
|
||||
if(!document.getElementById(lID))
|
||||
{
|
||||
var element = document.createElement(pName);
|
||||
element.src = pSrc;
|
||||
element.id=lID;
|
||||
if(arguments.length>=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<lLI.length;i++)
|
||||
{
|
||||
var lIsDir=lLI[i].getElementsByClassName('mini-icon')[0]
|
||||
.className.replace('mini-icon ','')==='directory'?true:false;
|
||||
|
||||
var lName=lLI[i].getElementsByClassName('name')[0].innerText;
|
||||
/* если это папка - выводим слово dir вместо размера*/
|
||||
var lSize=lIsDir?'dir':lLI[i].getElementsByClassName('size')[0].innerText;
|
||||
var lMode=lLI[i].getElementsByClassName('mode')[0].innerText;
|
||||
/* переводим права доступа в цыфровой вид
|
||||
* для хранения в localStorage
|
||||
*/
|
||||
lMode=CloudFunc.convertPermissionsToNumberic(lMode);
|
||||
|
||||
lFileTable[j++]={
|
||||
name:lName,
|
||||
size:lSize,
|
||||
mode:lMode
|
||||
};
|
||||
}
|
||||
return JSON.stringify(lFileTable);
|
||||
};
|
||||
|
||||
|
||||
/* если нет функции поиска по класам,
|
||||
* а её нет в IE,
|
||||
* - используем jquery
|
||||
* при необходимости
|
||||
* можна заменить на любой другой код
|
||||
*/
|
||||
if(!document.getElementsByClassName){
|
||||
CloudClient.jsload('//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js',function(){
|
||||
/* сохраняем переменную jQuery себе в область видимости */
|
||||
document.getElementsByClassName=function(pClassName){
|
||||
return $('.'+pClassName)[0];
|
||||
};
|
||||
$=window.jQuery;
|
||||
window.jQuery || CloudClient.jsload('jquery.min.js',
|
||||
function(){
|
||||
$=window.jQuery;
|
||||
document.getElementsByClassName=function(pClassName){
|
||||
return $('.'+pClassName)[0];
|
||||
};
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return CloudClient;
|
||||
});//(this,this.document);
|
||||
try{
|
||||
var Commander;
|
||||
window.onload=function(){
|
||||
'use strict';
|
||||
Commander=new CloudCommander();
|
||||
/* базовая инициализация*/
|
||||
Commander.init();
|
||||
/* привязываем клавиши к функциям */
|
||||
Commander.keyBinding();
|
||||
};
|
||||
}
|
||||
catch(err){}
|
||||
511
cloudfunc.js
511
cloudfunc.js
|
|
@ -1,511 +0,0 @@
|
|||
/* Модуль, содержащий функции, которые будут работать
|
||||
* и на клиенте и на сервере
|
||||
*
|
||||
* Привала названий:
|
||||
* 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'
|
||||
};
|
||||
|
||||
/*
|
||||
* Функция убирает последний слеш,
|
||||
* если он - последний символ строки
|
||||
*/
|
||||
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(pSize<l1BMAX)lShorted=pSize+'b';
|
||||
else if(pSize<l1KBMAX)lShorted=(pSize/l1BMAX) .toFixed(2)+'kb'
|
||||
else if(pSize<l1MBMAX)lShorted=(pSize/l1KBMAX).toFixed(2)+'mb'
|
||||
else if(pSize<l1GBMAX)lShorted=(pSize/l1MBMAX).toFixed(2)+'gb'
|
||||
else if(pSize<l1TBMAX)lShorted=(pSize/l1GBMAX).toFixed(2)+'tb'
|
||||
return lShorted;
|
||||
}
|
||||
|
||||
/* Функция парсит uid и имена пользователей
|
||||
* из переданного в строке вычитаного файла /etc/passwd
|
||||
* и возвращает массив обьектов имён и uid пользователей
|
||||
* @pPasswd_s - строка, в которой находиться файл /etc/passwd
|
||||
*/
|
||||
CloudFunc.getUserUIDsAndNames=function(pPasswd_s){
|
||||
var lUsers={name:'',uid:''};
|
||||
var lUsersData=[];
|
||||
var i=0;
|
||||
do{
|
||||
/* получаем первую строку */
|
||||
var lLine=pPasswd_s.substr(pPasswd_s,pPasswd_s.indexOf('\n')+1);
|
||||
if(lLine){
|
||||
/* удаляем первую строку из /etc/passwd*/
|
||||
pPasswd_s=pPasswd_s.replace(lLine,'');
|
||||
/* получаем первое слово строки */
|
||||
var lName=lLine.substr(lLine,lLine.indexOf(':'));
|
||||
lLine=lLine.replace(lName+':x:','');
|
||||
/* получаем uid*/
|
||||
var lUID=lLine.substr(lLine,lLine.indexOf(':'));
|
||||
if((lUID-0).toString()!=='NaN'){
|
||||
lUsers.name=lName;
|
||||
lUsers.uid=lUID;
|
||||
lUsersData[i++]=lUsers;
|
||||
console.log('uid='+lUID+' name='+lName);
|
||||
}
|
||||
}
|
||||
}while(pPasswd_s!=='');
|
||||
|
||||
return lUsersData;
|
||||
}
|
||||
/* Функция получает адреса каждого каталога в пути
|
||||
* возвращаеться массив каталогов
|
||||
* @url - адрес каталога
|
||||
*/
|
||||
CloudFunc._getDirPath=function(url)
|
||||
{
|
||||
var folders=new Array();
|
||||
var i=0;
|
||||
do{
|
||||
folders[i++]=url; url=url.substr(url,url.lastIndexOf('/'));
|
||||
}while(url!='');
|
||||
|
||||
/* сохраяем адрес предыдущего каталога */
|
||||
/*
|
||||
if(i>2){
|
||||
if(folders[0].lastIndexOf('/')===folders[0].length)
|
||||
LPrevDir=folders[1];
|
||||
else LPrevDir=folders[2];
|
||||
}else LPrevDir='/';
|
||||
*/
|
||||
/* ################################### */
|
||||
|
||||
/* Формируем ссылки на каждый каталог в пути */
|
||||
var lHref='<a class=links href=';
|
||||
var lTitle=' title=';
|
||||
var _l='>';
|
||||
var lHrefEnd='</a>';
|
||||
|
||||
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='<li class=fm_header>';
|
||||
lHeader+='<span class=mini-icon></span>';
|
||||
for(var i=0;i<pFileTableTitles.length;i++)
|
||||
{
|
||||
var lStr=pFileTableTitles[i];
|
||||
lHeader+='<span class='+lStr+'>'+
|
||||
lStr+
|
||||
'</span>';
|
||||
}
|
||||
lHeader+='</li>';
|
||||
|
||||
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='<li class=path>'+
|
||||
'<span class="path_icon clear-cache" id=clear-cache title="clear cache (Ctrl+D)"></span>'+
|
||||
'<a href="'+lFS_s+lNoJS_s+lRefreshPath+'">'+
|
||||
'<span class="path_icon ' + CloudFunc.REFRESHICON + '"' +
|
||||
' title="refresh (Ctrl+R)">' +
|
||||
'</span>'+
|
||||
'</a>'+
|
||||
'<span>'+lHtmlPath+'</span>'+
|
||||
'</li>';
|
||||
|
||||
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 += '<li class=current-file>'+
|
||||
'<span class="mini-icon directory">' +
|
||||
'</span>' +
|
||||
'<span class=name>' +
|
||||
'<a href="'+lFS_s+lNoJS_s +
|
||||
lDotDot +
|
||||
'">'+"..</a>" +
|
||||
'</span>' +
|
||||
'<span class=size><dir></span>'+
|
||||
'<span class=owner>.</span>' +
|
||||
'<span class=mode></span>' +
|
||||
'</li>';
|
||||
}
|
||||
var lLength=files.length;
|
||||
|
||||
for(var i=1;i<lLength;i++){
|
||||
lFileTable +='<li class>';
|
||||
lFileTable += '<span class="mini-icon ';
|
||||
/* если папка - выводим другую иконку */
|
||||
lFileTable += (files[i].size==='dir'?
|
||||
'directory':'text-file') +
|
||||
'">';
|
||||
lFileTable +='</span>';
|
||||
lFileTable +='<span class=name>' +
|
||||
'<a href="'+lFS_s+lNoJS_s +
|
||||
lPath+files[i].name +
|
||||
'"' +
|
||||
/* открываем файлы */
|
||||
/*в новой вкладке */
|
||||
(files[i].size==='dir'?'': ' target="_blank"')+
|
||||
/* если длина имени файла больше 16 символов
|
||||
* отрезаем лишнее, оставляя лишь 16,
|
||||
* и добавляем две точки и тайтл
|
||||
*/
|
||||
(files[i].name.length>16?
|
||||
' title="'+files[i].name+'">' +
|
||||
files[i].name.substr(
|
||||
files[i].name,16)+
|
||||
'..':'>'+files[i].name) +
|
||||
"</a>" +
|
||||
'</span>';
|
||||
/* если папка - не выводим размер */
|
||||
lFileTable +='<span class=size>' +
|
||||
(files[i].size==='dir'?
|
||||
'<dir>':
|
||||
/* если это файл - получаем
|
||||
* короткий размер
|
||||
*/
|
||||
CloudFunc.getShortedSize(
|
||||
files[i].size));
|
||||
lFileTable +='</span>' +
|
||||
'<span class=owner>' +
|
||||
(!files[i].uid?'root':files[i].uid) +
|
||||
'</span>' +
|
||||
'<span class=mode>' +
|
||||
/* конвертируем названия разрешений
|
||||
* из числового формата в буквенный
|
||||
* при этом корневой каталог не трогаем
|
||||
* по скольку в нём и так всё уже
|
||||
* установлено еще на сервере
|
||||
*/
|
||||
(//lPath==='/'?files[i].mode:
|
||||
CloudFunc.convertPermissionsToSymbolic(files[i].mode)) +
|
||||
'</span>';
|
||||
lFileTable +='</li>';
|
||||
}
|
||||
|
||||
/* если клавиши назначены и
|
||||
* мы в корневом каталоге и
|
||||
* верхний файл еще не выделен -
|
||||
* выделяем верхний файл
|
||||
*/
|
||||
if(pKeyBinded && lPath==='/'&&
|
||||
lFileTable.indexOf('<li class=current-file>')<0){
|
||||
lFileTable=lFileTable.replace('<li class>','<li class=current-file>');
|
||||
}
|
||||
|
||||
|
||||
|
||||
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){
|
||||
/* если мы на клиенте */
|
||||
}
|
||||
59
index.html
59
index.html
|
|
@ -1,59 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<!-- moblie first design -->
|
||||
<meta content="width=device-width,initial-scale=1" name="viewport" />
|
||||
<title>Cloud Commander</title>
|
||||
|
||||
<!--
|
||||
<link rel="stylesheet" type="text/css" href="http://dl.dropbox.com/u/74212301/mnemonia/css/reset.css">
|
||||
<link rel="stylesheet" type="text/css" href="http://rastacoding.kodingen.com/online/header/css/button.css">
|
||||
-->
|
||||
<link rel="stylesheet" href="/reset.css">
|
||||
<link rel="stylesheet" href="/style.css">
|
||||
<link rel="stylesheet" href="//fonts.googleapis.com/css?family=Droid+Sans+Mono">
|
||||
<!--
|
||||
<script async src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
|
||||
<script async src=http://dl.dropbox.com/u/74212301/mnemonia/js/prefixfree.min.js></script>
|
||||
<script async src="//modernizr.com/downloads/modernizr-2.5.3.js"></script>
|
||||
<script async src="http://dl.dropbox.com/u/78163899/mnemonia/js/css3-mediaqueries.js"></script>
|
||||
<script async src="dist/html5shiv.js"></script>
|
||||
-->
|
||||
<!--[if lt IE 9]>
|
||||
<![endif]-->
|
||||
</head>
|
||||
<body>
|
||||
<!--
|
||||
<input placeholder=bin style="width:100%;position:relative;top:-1px">
|
||||
-->
|
||||
<!--
|
||||
http://gtmetrix.com/reports/cloudcmd.cloudfoundry.com/b8hQTONq
|
||||
-->
|
||||
<a class="yellow hidden">Cloud Commander</a>
|
||||
<ul class="menu hidden">
|
||||
<li>
|
||||
<!-- http://css-tricks.com/examples/IconFont/ -->
|
||||
<a href=settings onclick="return false;">
|
||||
<span class="menu_icon settings hidden"></span>
|
||||
</a>
|
||||
<a href=refresh onclick="return false;">
|
||||
<span class="menu_icon refresh" id=refresh></span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div id=fm class=no-js>
|
||||
</div>
|
||||
<div id=keyspanel class=hidden>
|
||||
<button>F1 - help</button>
|
||||
<button>F2 - rename</button>
|
||||
<button>F3 - view</button>
|
||||
<button>F4 - edit</button>
|
||||
<button>F5 - copy</button>
|
||||
<button>F6 - move</button>
|
||||
<button>F7 - make dir</button>
|
||||
<button>F8 - remove</button>
|
||||
</div>
|
||||
<script src=/client.js></script>
|
||||
</body>
|
||||
</html>
|
||||
81
minify.js
81
minify.js
|
|
@ -1,81 +0,0 @@
|
|||
/* Модуль сжатия js-скриптов*/
|
||||
/*
|
||||
https://github.com/GoalSmashers/clean-css
|
||||
*/
|
||||
exports.jsScripts=jsScripts;
|
||||
|
||||
function jsScripts(){
|
||||
'use strict';
|
||||
|
||||
/* подключаем модуль uglify-js
|
||||
* если его нет - дальнейшая
|
||||
* работа модуля не имеет смысла
|
||||
*/
|
||||
try{
|
||||
var jsp = require("uglify-js").parser;
|
||||
var pro = require("uglify-js").uglify;
|
||||
}catch(error){
|
||||
return console.log('ERROR. error loading minificatoin js\n' +
|
||||
'to use minification you need to install uglify-js\n' +
|
||||
'npm install uglify-js\n' +
|
||||
'https://github.com/mishoo/UglifyJS\n' +
|
||||
error);
|
||||
}
|
||||
|
||||
var fs = require('fs');
|
||||
|
||||
/* Константы */
|
||||
var CLIENT_JS='client.js';
|
||||
var CLOUDFUNC_JS='cloudfunc.js';
|
||||
|
||||
console.log('reading file ' + CLIENT_JS+'...');
|
||||
fs.readFile(CLIENT_JS,fileReaded(CLIENT_JS));
|
||||
|
||||
console.log('reading file ' + CLOUDFUNC_JS+'...');
|
||||
fs.readFile(CLOUDFUNC_JS,fileReaded(CLOUDFUNC_JS));
|
||||
|
||||
/* Функция создаёт асинхроную версию
|
||||
* для чтения файла
|
||||
* @pFileName - имя считываемого файла
|
||||
*/
|
||||
function fileReaded(pFileName){
|
||||
return function(error,data){
|
||||
/* функция в которую мы попадаем,
|
||||
* если данные считались
|
||||
*/
|
||||
var dataReaded=function(){
|
||||
console.log('file ' + pFileName + ' readed');
|
||||
|
||||
/*********************************/
|
||||
/* сжимаем код через uglify-js */
|
||||
var orig_code = data.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 final_code = pro.gen_code(ast); // compressed code here
|
||||
/*********************************/
|
||||
|
||||
var minFileName=pFileName.replace('.js','.min.js');
|
||||
/* если мы сжимаем client.js -
|
||||
* меняем строку cloudfunc.js на
|
||||
* cloudfunc.min.js и выводим сообщение
|
||||
* если другой файл - ничего не деалем
|
||||
*/
|
||||
(pFileName===CLIENT_JS)?
|
||||
console.log('file name of '+CLOUDFUNC_JS+' in '+CLIENT_JS+' changed. size:',
|
||||
(final_code=final_code.replace(CLOUDFUNC_JS,
|
||||
CLOUDFUNC_JS.replace('.js',
|
||||
'.min.js'))).length):
|
||||
'';
|
||||
var fileWrited=function(error){
|
||||
console.log(error?error:('file '+minFileName+' writed...'));
|
||||
};
|
||||
|
||||
/* записываем сжатый js-скрипт*/
|
||||
fs.writeFile(minFileName, final_code, fileWrited);
|
||||
};
|
||||
|
||||
error?console.log(error):dataReaded();
|
||||
};
|
||||
}
|
||||
};
|
||||
115
reset.css
115
reset.css
|
|
@ -1,115 +0,0 @@
|
|||
/*
|
||||
* HTML5 Boilerplate
|
||||
*
|
||||
* What follows is the result of much research on cross-browser styling.
|
||||
* Credit left inline and big thanks to Nicolas Gallagher, Jonathan Neal,
|
||||
* Kroc Camen, and the H5BP dev community and team.
|
||||
*
|
||||
* Detailed information about this CSS: h5bp.com/css
|
||||
*
|
||||
* ==|== normalize ==========================================================
|
||||
*/
|
||||
|
||||
|
||||
/* =============================================================================
|
||||
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; }
|
||||
}
|
||||
563
server.js
563
server.js
|
|
@ -1,563 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
/* Обьект содержащий все функции и переменные
|
||||
* серверной части Cloud Commander'а
|
||||
*/
|
||||
var CloudServer={
|
||||
/* функция, которая генерирует заголовки
|
||||
* файлов, отправляемые сервером клиенту
|
||||
*/
|
||||
generateHeaders :function(){},
|
||||
/* функция высылает
|
||||
* данные клиенту
|
||||
*/
|
||||
sendResponse :function(){},
|
||||
/* Структура содержащая функции,
|
||||
* и переменные, в которых
|
||||
* говориться о поддерживаемых
|
||||
* браузером технологиях
|
||||
*/
|
||||
BrowserSuport :{},
|
||||
/* Обьект для работы с кэшем */
|
||||
Cashe :{},
|
||||
/* Обьект через который
|
||||
* выполняеться сжатие
|
||||
* скриптов и стилей
|
||||
*/
|
||||
Minify :{},
|
||||
/* Асоциативный масив обьектов для
|
||||
* работы с ответами сервера
|
||||
* высылаемыми на запрос о файле и
|
||||
* хранащий информацию в виде
|
||||
* Responces[name]=responce;
|
||||
*/
|
||||
Responses :{},
|
||||
|
||||
/* ПЕРЕМЕННЫЕ */
|
||||
/* Поддержка браузером JS*/
|
||||
NoJS :true,
|
||||
/* обьект содержит данные
|
||||
* о необходимости сжатия
|
||||
* данных и скриптов
|
||||
*/
|
||||
Minimize :{
|
||||
scriptSize:false,
|
||||
styleSize:false
|
||||
},
|
||||
/* Поддержка gzip-сжатия
|
||||
* браузером
|
||||
*/
|
||||
Gzip :undefined,
|
||||
|
||||
/* КОНСТАНТЫ */
|
||||
/* index.html */
|
||||
INDEX :'index.html'
|
||||
};
|
||||
|
||||
/*
|
||||
* Обьект для работы с кэшем
|
||||
* аналог клиентского обьекта
|
||||
* с тем отличием, что в нём
|
||||
* будут храниться серверные
|
||||
* данные, такие как файлы
|
||||
* отдаваемые клиенту
|
||||
* (файлы проэкта по большому
|
||||
* счёту, для ускорения
|
||||
* первичной загрузки)
|
||||
*/
|
||||
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={
|
||||
scripts : function(){
|
||||
if(CloudServer.Minimize.scriptSize){
|
||||
var lMinify = require('./minify');
|
||||
lMinify.jsScripts();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//var DirContent;
|
||||
var LeftDir='/';
|
||||
var RightDir=LeftDir;
|
||||
//var LPrevDir;
|
||||
//var RPrevDir;
|
||||
|
||||
var Fs = require('fs'); /* модуль для работы с файловой системой*/
|
||||
var Path = require('path'); /* модуль для работы с путями*/
|
||||
var Zlib = require('zlib'); /* модуль для сжатия данных gzip-ом*/
|
||||
var CloudFunc=CloudServer.Minimize.scripts?/* если стоит минификация*/
|
||||
require('./cloudfunc.min'):/* добавляем сжатый - иначе обычный */
|
||||
require('./cloudfunc'); /* модуль с функциями */
|
||||
|
||||
|
||||
/* конструктор*/
|
||||
CloudServer.init=(function(){
|
||||
/* Переменная в которой храниться кэш*/
|
||||
CloudServer.Cache.setAllowed(false);
|
||||
CloudServer.Minimize.scriptSize=true;
|
||||
/* Если нужно минимизируем скрипты */
|
||||
CloudServer.Minify.scripts();
|
||||
});
|
||||
|
||||
|
||||
/* создаём сервер на порту 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='img/png';
|
||||
/* загружаем json*/
|
||||
else if(CloudFunc.checkExtension(pName,'json'))
|
||||
lType='application/json';
|
||||
else if(CloudFunc.checkExtension(pName,'html'))
|
||||
lType='text/html';
|
||||
/* если это неизвестный тип файла -
|
||||
* высылаем его просто как текст
|
||||
*/
|
||||
else lType='text/plain';
|
||||
|
||||
return {
|
||||
'Content-Type': lType+'; 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-сжатие при первом заходе на сайт
|
||||
*/
|
||||
if (lAcceptEncoding &&
|
||||
lAcceptEncoding.match(/\bgzip\b/)){
|
||||
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,
|
||||
* ни о том, что это корневой
|
||||
* каталог - загружаем файлы проэкта
|
||||
*/
|
||||
console.log(lFS_s+pathname);
|
||||
if(pathname.indexOf(lFS_s)<0 &&
|
||||
pathname.indexOf(lNoJS_s)<0 &&
|
||||
pathname!=='/'){
|
||||
/* если имена файлов проекта - загружаем их*/
|
||||
/* убираем слеш и читаем файл с текущец директории*/
|
||||
lName=Path.basename(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;
|
||||
//DirContent=fs.readdirSync(LeftDir);
|
||||
|
||||
/* если встретиться пробел -
|
||||
* меня код символа пробела на пробел
|
||||
*/
|
||||
|
||||
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{
|
||||
/*
|
||||
* сохраним указатель на 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+='/';
|
||||
}
|
||||
//DirContent=
|
||||
pFiles=pFiles.sort();
|
||||
|
||||
lJSON[0]={path:LeftDir,size:'dir'};
|
||||
var fReturnFalse=function returnFalse(){return false;};
|
||||
for(var i=0;i<pFiles.length;i++)
|
||||
{
|
||||
/* Получаем информацию о файле*/
|
||||
var lStats;
|
||||
try{
|
||||
lStats=Fs.statSync(RightDir+pFiles[i]);
|
||||
}catch(err){
|
||||
console.log(err);
|
||||
lStats={
|
||||
'mode':undefined,
|
||||
'size':undefined,
|
||||
'isDirectory':fReturnFalse
|
||||
};
|
||||
}
|
||||
/*
|
||||
*Переводим права доступа в 8-ричную систему
|
||||
*/
|
||||
var lMode=(lStats.mode-0).toString(8);
|
||||
|
||||
/* Если папка - выводим пиктограмму папки */
|
||||
if(lStats.isDirectory())
|
||||
{
|
||||
lJSONFile={'name':pFiles[i],'size':'dir','uid':lStats.uid,'mode':lMode};
|
||||
lJSON[i+1]=lJSONFile;
|
||||
}
|
||||
/* В противоположном случае - файла */
|
||||
else
|
||||
{
|
||||
lJSONFile={'name':pFiles[i],'uid':lStats.uid,'size':lStats.size,'mode':lMode};
|
||||
lJSON[i+1]=lJSONFile;
|
||||
}
|
||||
}
|
||||
|
||||
/* заголовок ответа сервера */
|
||||
var lHeader;
|
||||
var lList;
|
||||
/* если js недоступен */
|
||||
/* если javascript отключен вылылаем html-код
|
||||
* и прописываем соответствующие заголовки
|
||||
*/
|
||||
if(CloudServer.NoJS){
|
||||
var lPanel=CloudFunc.buildFromJSON(lJSON);
|
||||
lList='<ul id=left class=panel>';
|
||||
lList+=lPanel;
|
||||
lList+='</ul>';
|
||||
|
||||
lList+='<ul id=right class="panel hidden">';
|
||||
lList+=lPanel;
|
||||
lList+='</ul>';
|
||||
try{
|
||||
var lIndex;
|
||||
/* пробуем достать данные из кэша
|
||||
* с жатием или без, взависимости
|
||||
* от настроек
|
||||
*/
|
||||
var lFileData=CloudServer.Cache.get(CloudServer.INDEX);
|
||||
/* если их нет там - вычитываем из файла*/
|
||||
if(!lFileData){
|
||||
lIndex=Fs.readFileSync(CloudServer.INDEX);
|
||||
/* и сохраняем в кэш */
|
||||
CloudServer.Cache.set(CloudServer.INDEX,lIndex);
|
||||
}else lIndex=lFileData;
|
||||
|
||||
/* если выбрана опция минифизировать скрпиты
|
||||
* меняем в index.html обычный client.js на
|
||||
* минифицированый
|
||||
*/
|
||||
lIndex=lIndex.toString();
|
||||
CloudServer.Minimize.scriptSize?
|
||||
lIndex=lIndex.replace('client.js','client.min.js'):'';
|
||||
|
||||
lIndex=lIndex.toString().replace('<div id=fm class=no-js>','<div id=fm class=no-js>'+lList);
|
||||
/* меняем title */
|
||||
lIndex=lIndex.replace('<title>Cloud Commander</title>',
|
||||
'<title>'+CloudFunc.setTitle()+'</title>');
|
||||
/* отображаем панель быстрых клавишь */
|
||||
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();
|
||||
316
style.css
316
style.css
|
|
@ -1,316 +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');
|
||||
}
|
||||
body{
|
||||
font:16px "Droid Sans Mono";
|
||||
}
|
||||
/* убираем элементы,
|
||||
* которые будут работать только,
|
||||
* если есть js
|
||||
*/
|
||||
.no-js .refresh-icon{
|
||||
display:none;
|
||||
}
|
||||
|
||||
.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(//dl.dropbox.com/u/74212301/mnemonia/images/icons/spinner.gif);
|
||||
position:relative;
|
||||
top:1px;
|
||||
}
|
||||
.error:hover{
|
||||
color:rgba(222, 41, 41, 0.81);
|
||||
}
|
||||
.refresh-icon{
|
||||
background:url(//dl.dropbox.com/u/78163899/mnemonia/images/icons/panel_refresh.png) no-repeat;
|
||||
}
|
||||
.refresh-icon:active{
|
||||
/*background-position-y: -15px;*/
|
||||
background:url(//dl.dropbox.com/u/78163899/mnemonia/images/icons/panel_refresh.png) 0 -15px no-repeat;
|
||||
}
|
||||
.clear-cache{
|
||||
background:url(//dl.dropbox.com/u/78163899/mnemonia/images/icons/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('//dl.dropbox.com/u/74212301/mnemonia/images/icons/dir.png');
|
||||
background-repeat: no-repeat;
|
||||
background-position: 0 0;
|
||||
}
|
||||
.text-file{
|
||||
/*list-style-image*/
|
||||
background-image:url('//dl.dropbox.com/u/74212301/mnemonia/images/icons/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:50%;
|
||||
}
|
||||
#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;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue