diff --git a/README.md b/README.md new file mode 100644 index 00000000..0fedc950 --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +Cloud-Commander +=============== \ No newline at end of file diff --git a/client.js b/client.js new file mode 100644 index 00000000..f052ff42 --- /dev/null +++ b/client.js @@ -0,0 +1,978 @@ +/* Функция которая возвратит обьект CloudCommander + * @window - обьект window + * @document - обьект document + * @CloudFunc - обьект содержащий общий функционал + * клиентский и серверный + */ +//var CloudCommander=(function(window,document){ + +var document,window; + +var CloudCommander=(function(){ +"use strict"; + +/* если функции console.log нет - создаём заглушку */ + +var console; +if(!window)window={console:{log:function(pParam){return pParam;}}}; +else if(window && !window.console){ + console={ + 'log':function(param){ + return param; + } + }; +}else console=window.console; + +/* + window.jQuery || document.write(' + + \ No newline at end of file diff --git a/minify.js b/minify.js new file mode 100644 index 00000000..3b8b8abd --- /dev/null +++ b/minify.js @@ -0,0 +1,81 @@ +/* Модуль сжатия 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(); + }; + } +}; \ No newline at end of file diff --git a/reset.css b/reset.css new file mode 100644 index 00000000..4dd740d9 --- /dev/null +++ b/reset.css @@ -0,0 +1,115 @@ +/* + * 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; } +} \ No newline at end of file diff --git a/server.js b/server.js new file mode 100644 index 00000000..04f9e310 --- /dev/null +++ b/server.js @@ -0,0 +1,563 @@ +"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','
'+lList); + /* меняем title */ + lIndex=lIndex.replace('Cloud Commander', + ''+CloudFunc.setTitle()+''); + /* отображаем панель быстрых клавишь */ + lList=lIndex; + /* если браузер поддерживает gzip-сжатие*/ + lHeader=CloudServer.generateHeaders('text/html',CloudServer.Gzip); + }catch(error){console.log(error);} + }else{ + /* в обычном режиме(когда js включен + * высылаем json-структуру файлов + * с соответствующими заголовками + */ + lList=JSON.stringify(lJSON); + lHeader=CloudServer.generateHeaders('application/json',CloudServer.Gzip); + } + /* если браузер поддерживает gzip-сжатие - сжимаем данные*/ + if(CloudServer.Gzip){ + Zlib.gzip(lList,CloudServer.getGzipDataFunc(lHeader,CloudServer.INDEX)); + } + /* если не поддерживаеться - отсылаем данные без сжатия*/ + else + CloudServer.sendResponse(lHeader,lList,CloudServer.INDEX); + } + else + { + console.log(pError); + CloudServer.sendResponse('OK',pError.toString()); + } +}; + +/* Функция генерирует функция считывания файла + * таким образом, что бы у нас было + * имя считываемого файла + * @pName - полное имя файла + */ +CloudServer.getReadFileFunc = function(pName){ +/* + * @pError - ошибка + * @pData - данные + * @pFromFile - прочитано с файла bool + */ + var lReadFile=function(pError,pData,pFromCache_b){ + if (!pError){ + console.log('file ' + pName + ' readed'); + + /* берём из кэша данные файла + * если их нет в кэше - + * сохраняем + */ + if(!pFromCache_b && CloudServer.Cache.isAllowed) + CloudServer.Cache.set(pName,pData); + /* если кэш есть + * сохраняем его в переменную + * которая до этого будет пустая + * по скольку мы будем вызывать этот метод + * сами, ведь файл уже вычитан + */ + + var lHeader=CloudServer.generateHeaders(pName,CloudServer.Gzip); + /* если браузер поддерживает gzip-сжатие - сжимаем данные*/ + if(CloudServer.Gzip &&!pFromCache_b){ + /* сжимаем содержимое */ + Zlib.gzip(pData,CloudServer.getGzipDataFunc(lHeader,pName)); + } + else{ + /* высылаем несжатые данные */ + CloudServer.sendResponse(lHeader,pData,pName); + } + } + else + { + console.log(pError.path); + if(pError.path!='passwd.json') + { + console.log(pError); + CloudServer.sendResponse('OK',pError.toString()); + }else{ + CloudServer.sendResponse('OK','passwd.json'); + } + } + }; + return lReadFile; +}; + +/* Функция получает сжатые данные + * @pHeader - заголовок файла + */ +CloudServer.getGzipDataFunc=function(pHeader,pName){ + return function(error,pResult){ + if(!error){ + /* отправляем сжатые данные + * вместе с заголовком + */ + /* если установлена работа с кэшем + * сохраняем сжатые данные + */ + if(CloudServer.Cache.isAllowed){ + /* устанавливаем кєш */ + console.log(pName+' gziped'); + CloudServer.Cache.set(pName+'_gzip',pResult); + } + CloudServer.sendResponse(pHeader,pResult,pName); + } + else{ + console.log(error); + CloudServer.sendResponse(pHeader,error); + } + }; +}; +/* Функция высылает ответ серверу + * @pHead - заголовок + * @pData - данные + * @pName - имя отсылаемого файла + */ +CloudServer.sendResponse = function(pHead, pData,pName){ + /* если у нас есть указатель на responce + * для соответствующего файла - + * высылаем его + */ + var lResponse=CloudServer.Responses[pName]; + if(lResponse){ + lResponse.writeHead(200,pHead); + lResponse.end(pData); + console.log(pName+' sended'); + } +}; + +CloudServer.start(); \ No newline at end of file diff --git a/style.css b/style.css new file mode 100644 index 00000000..28a49a52 --- /dev/null +++ b/style.css @@ -0,0 +1,316 @@ +/* +@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; + } +} \ No newline at end of file