From df399b34de1bb72484407e2b72a7482ce4b61e6a Mon Sep 17 00:00:00 2001 From: coderaiser Date: Thu, 7 Jun 2012 13:33:42 +0000 Subject: [PATCH] cloud commander --- README.md | 2 + client.js | 978 +++++++++++++++++++++++++++++++++++++++++++++++++++ cloudfunc.js | 511 +++++++++++++++++++++++++++ index.html | 59 ++++ minify.js | 81 +++++ reset.css | 115 ++++++ server.js | 563 +++++++++++++++++++++++++++++ style.css | 316 +++++++++++++++++ 8 files changed, 2625 insertions(+) create mode 100644 README.md create mode 100644 client.js create mode 100644 cloudfunc.js create mode 100644 index.html create mode 100644 minify.js create mode 100644 reset.css create mode 100644 server.js create mode 100644 style.css 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