minor changes

This commit is contained in:
coderaiser 2012-08-06 14:23:20 -04:00
commit 42d0570ef0
27 changed files with 7815 additions and 2042 deletions

View file

@ -1,11 +0,0 @@
language: node_js
node_js:
#- 0.4 #jshint fails to install (no gzip, jshint test not working out)
- 0.6
- 0.8
notifications:
webhooks:
#http://requestb.in/12h5bl71
urls:
# http://webhooks.jit.su/deploy ##
- http://webhooks.nodejitsu.com/1/deploy

View file

@ -1,3 +1,43 @@
2012.07.*, Version 0.1.5
* Added tab support.
* Fixed bug with Path links.
* From now CodeMirror js files loads, when f4 key pressed.
* Fixed bug with showing CodeMirror after first show.
* Added ability to read files in CodeMirror.
* Added ability rename files.
* Fixed bug with CodeMirror vertical scroll bar.
* Added loading image when file going to be edited.
* All sync functions changed to async equivalents.
* On f4 key pressed when current-file is folder
CodeMirror opens json data of folder.
* Fixed bug with response when we have no rihgts
read dir server sends 404 response for now,
not 200 ok.
* Fixed bug with forming error of loading dir.
Was : "not found".
Now : "Error: EACCES, readdir '/root'"
* Fixed bug with showing loading spinner, when f4 key
pressed couple times and CodeMirror not loaded fully.
* Setted readOnly mode, when directory opened in CodeMirror.
* Added api for getting curent file, getting active
and passive panels and show/hide any of panels.
2012.07.27, Version 0.1.4
* Added local version of Droids font for offline mode

829
client.js
View file

@ -1,829 +0,0 @@
/* Функция которая возвратит обьект CloudCommander
* @window - обьект window
* @document - обьект document
* @CloudFunc - обьект содержащий общий функционал
* клиентский и серверный
*/
var CloudCommander=(function(){
"use strict";
/* Клиентский обьект, содержащий функциональную часть*/
var CloudClient={
/* Конструктор CloudClient, который
* выполняет весь функционал по
* инициализации
*/
init :function(){},
keyBinding :function(){},/* функция нажатий обработки клавишь */
Editor :function(){},/* function loads and shows editor */
Viewer :function(){},/* function loads and shows viewer */
keyBinded :false,/* оброботка нажатий клавишь установлена*/
_loadDir :function(){},
/*
* Функция привязываеться ко всем ссылкам и
* загружает содержимое каталогов
*/
/* Обьект для работы с кэшем */
Cashe :{},
/* ПРИВАТНЫЕ ФУНКЦИИ */
/* функция загружает json-данные о файловой системе */
_ajaxLoad :function(){},
/* Функция генерирует JSON из html-таблицы файлов */
_getJSONfromFileTable :function(){},
/* функция меняет ссыки на ajax-овые */
_changeLinks :function(){},
/* ОБЬЕКТЫ */
/* обьект, который содержит функции для отображения картинок*/
_images :{},
/* КОНСТАНТЫ*/
/* название css-класа текущего файла*/
CURRENT_FILE :'current-file',
LIBDIR :'/lib/',
LIBDIRCLIENT :'/lib/client/',
/* height of Cloud Commander
* seting up in init()
*/
HEIGHT :0
};
/*
* Обьект для работы с кэшем
* в него будут включены функции для
* работы с LocalStorage, webdb,
* indexed 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(){
/* loading keyBinding module and start it */
Util.jsload(CloudClient.LIBDIRCLIENT+'keyBinding.js',function(){
CloudCommander.keyBinding();
});
});
/* function loads and shows editor */
CloudClient.Editor = (function(){
/* loading CloudMirror plagin */
Util.jsload(CloudClient.LIBDIRCLIENT +
'editor.js',{
onload:(function(){
CloudCommander.Editor.Keys();
})
});
});
/* function loads and shows viewer */
CloudClient.Viewer = (function(){
Util.jsload(CloudClient.LIBDIRCLIENT +
'viewer.js',{
onload: (function(){
CloudCommander.Viewer.Keys();
})
});
});
/*
* Функция привязываеться ко всем ссылкам и
* загружает содержимое каталогов
*/
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].textContent;
}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].textContent==='..' &&
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;
}
}
/* если мы попали сюда с энтера*/
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 = lCurrentFile[0].parentElement;
/* убираем слэш с имени каталога*/
pDirName=pDirName.replace('/','');
var lRootDir = document.getElementById(pDirName + '(' + lPanel.id + ')');
/* if found li element with ID directory name
* set it to current file
*/
lRootDir &&
!(lCurrentFile[0].className = '') &&
(lRootDir.className = CloudClient.CURRENT_FILE);
});
/* глобальные переменные */
var LoadingImage;
var ErrorImage;
var CloudFunc, $;
/* Конструктор CloudClient, который
* выполняет весь функционал по
* инициализации
*/
CloudClient.init=(function()
{
/* меняем title
* если js включен - имена папок отображать необязательно...
* а может и обязательно при переходе, можно будет это сделать
*/
var lTitle=document.getElementsByTagName('title');
if(lTitle.length>0)lTitle[0].textContent='Cloud Commander';
/* загружаем jquery: */
CloudClient.jsload('//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js',{
onload: function(){
$ = window.jQuery;
},
onerror: function(){
CloudClient.jsload('lib/client/jquery.js');
/*
* if could not load jquery from google server
* maybe we offline, load font from local
* directory
*/
CloudClient.cssSet({id:'local-droids-font',
element : document.head,
inner : '@font-face {font-family: "Droid Sans Mono";' +
'font-style: normal;font-weight: normal;' +
'src: local("Droid Sans Mono"), local("DroidSansMono"),'+
' url("font/DroidSansMono.woff") format("woff");}'
});
}
});
/* загружаем общие функции для клиента и сервера*/
CloudClient.jsload(CloudClient.LIBDIR+'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();
/* устанавливаем размер высоты таблицы файлов
* исходя из размеров разрешения экрана
*/
/* выделяем строку с первым файлом */
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','');
/* формируем и округляем высоту экрана
* при разрешениии 1024x1280:
* 658 -> 700
*/
var lHeight=window.screen.height - (window.screen.height/3).toFixed();
lHeight=(lHeight/100).toFixed()*100;
CloudClient.HEIGHT = lHeight;
CloudClient.cssSet({id:'show_2panels',
element:document.head,
inner:'#left{width:46%;}' +
'.panel{height:' + lHeight +'px'
});
});
/* функция меняет ссыки на 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 lREFRESHICON=0;
/* путь в ссылке, который говорит
* что js отключен
*/
var lNoJS_s = CloudFunc.NOJS;
var lFS_s = CloudFunc.FS;
for(var i=0;i<a.length;i++)
{
/* если ссылка на папку, а не файл */
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);
/* устанавливаем обработчики на строку на одинарное и
* двойное нажатие на левую кнопку мышки
*/
else{
try{
var lLi = a[i].parentElement.parentElement;
lLi.onclick = CloudClient._setCurrent();
lLi.ondblclick = CloudClient._loadDir(link);
lLi.id = (a[i].title ? a[i].title : a[i].textContent) +
'(' + pPanelID + ')';
}catch(error){console.log(error);}
}
}
}
};
/*
* Функция загружает json-данные о Файловой Системе
* через ajax-запрос.
* @path - каталог для чтения
* @pNeedRefresh - необходимость обновить данные о каталоге
*/
CloudClient._ajaxLoad=function(path, pNeedRefresh)
{
/* Отображаем красивые пути */
/* added supporting of russian language */
var lPath=decodeURI(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');
} else
ErrorImage.title = jqXHR.responseText;
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);
};
/*
* Function gets id by src
* from http://domain.com/1.js to
* 1_js
*/
CloudClient._getIdBySrc = function(pSrc){
var lID=pSrc.replace(pSrc.substr(pSrc,
pSrc.lastIndexOf('/')+1),
'');
/* убираем точку*/
return lID.replace('.','_');
};
/*
* Функция создаёт элемент и
* загружает файл с src.
* @pName - название тэга
* @pSrc - путь к файлу
* @pFunc - обьект, содержаий одну из функций
* или сразу две onload и onerror
* {onload: function(){}, onerror: function();}
* @pStyle - стиль
* @pId - id
* @pElement - элемент, дочерним которо будет этот
* @pParams_o = {name: '', src: ' ',func: '', style: '', id: '', element: '',
async: false}
*/
CloudClient._anyload = function(pParams_o)
{
/* убираем путь к файлу, оставляя только название файла */
var lID = pParams_o.id;
var lSrc = pParams_o.src;
var lFunc = pParams_o.func;
var lAsync = pParams_o.async;
if(!lID){
lID = this._getIdBySrc(lSrc);
}
var element = document.getElementById(lID);
/* если скрипт еще не загружен */
if(!element)
{
element = document.createElement(pParams_o.name);
/* if working with external css
* using href in any other case
* using src
*/
pParams_o.name === 'link' ?
element.href = lSrc
: element.src = lSrc;
element.id=lID;
/* if passed arguments function
* then it's onload by default
*/
if(pParams_o.func)
if(typeof lFunc === 'function'){
element.onload = lFunc;
/* if object - then onload or onerror */
}else if (typeof lFunc === 'object') {
if(lFunc.onload &&
typeof lFunc.onload === 'function')
element.onload = lFunc.onload;
if(lFunc.onerror &&
typeof lFunc.onerror === 'function')
element.onerror = (function(){
(pParams_o.element || document.body)
.removeChild(element);
lFunc.onerror();
});
}
if(pParams_o.style){
element.style.cssText=pParams_o.style;
}
if(lAsync || lAsync === undefined)
element.async = true;
(pParams_o.element || document.body).appendChild(element);
}
/* если js-файл уже загружен
* запускаем функцию onload
*/
else if(lFunc && typeof lFunc==='function'){
try{
lFunc();
}catch(error){console.log(error);}
}
return element;
};
/* Функция загружает js-файл */
CloudClient.jsload = function(pSrc,pFunc,pStyle,pId,pAsync)
{
CloudClient._anyload({
name : 'script',
src : pSrc,
func : pFunc,
stle : pStyle,
id : pId,
async: pAsync
});
};
/* Функция создаёт елемент style и записывает туда стили
* @pParams_o - структура параметров, заполняеться таким
* образом: {src: ' ',func: '', id: '', element: '', inner: ''}
* все параметры опциональны
*/
CloudClient.cssSet = function(pParams_o){
pParams_o.name = 'style';
pParams_o.element = pParams_o.element || document.head;
var lElem=CloudClient._anyload(pParams_o);
pParams_o.inner &&
(lElem.innerHTML = pParams_o.inner);
};
/* Function loads external css files
* @pParams_o - структура параметров, заполняеться таким
* образом: {src: ' ',func: '', id: '', element: '', inner: ''}
* все параметры опциональны
*/
CloudClient.cssLoad = function(pParams_o){
pParams_o.name = 'link';
pParams_o.element = pParams_o.element || document.head;
var lElem=CloudClient._anyload(pParams_o);
lElem &&
(lElem.rel = 'stylesheet');
pParams_o.inner &&
(lElem.innerHTML = pParams_o.inner);
};
/*
* Функция генерирует JSON из html-таблицы файлов и
* используеться при первом заходе в корень
*/
CloudClient._getJSONfromFileTable=function()
{
var lLeft=document.getElementById('left');
var lPath=document.getElementsByClassName('path')[0].textContent;
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];
lName &&
(lName = lName.getElementsByTagName('a'));
/* if found link to folder
* cheking is it a full name
* or short
*/
/* if short we got title
* if full - getting textConent
*/
lName.length &&
(lName = lName[0]);
lName.title &&
(lName = lName.title) ||
(lName = lName.textContent);
/* если это папка - выводим слово dir вместо размера*/
var lSize=lIsDir?'dir':lLI[i].getElementsByClassName('size')[0].textContent;
var lMode=lLI[i].getElementsByClassName('mode')[0].textContent;
/* переводим права доступа в цыфровой вид
* для хранения в 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',{
onload: function(){
/* сохраняем переменную jQuery себе в область видимости */
document.getElementsByClassName=function(pClassName){
return window.jQuery('.'+pClassName)[0];
};
},
onerror: function(){
CloudClient.jsload(CloudClient.LIBDIRCLIENT + 'jquery.js',
function(){
document.getElementsByClassName=function(pClassName){
return window.jQuery('.'+pClassName)[0];
};
});
}
});
}
return CloudClient;
})();
try{
window.onload=function(){
'use strict';
/* базовая инициализация*/
CloudCommander.init();
/* привязываем клавиши к функциям */
CloudCommander.keyBinding();
CloudCommander.Editor();
CloudCommander.Viewer();
};
}
catch(err){}

View file

@ -1,121 +1,185 @@
var CloudCommander, CodeMirror;
var CloudCommander, CloudFunc, CodeMirror;
/* object contains editors CodeMirror
* and later will be Ace
*/
CloudCommander.Editor = {};
CloudCommander.Editor.CodeMirror = {
load: (function(){ /* function loads CodeMirror js and css files */
/* function shows editor */
var showEditor = function (pParent){
return function(){
if (!document.getElementById('CloudEditor')) {
var lEditor=document.createElement('div');
lEditor.id ='CloudEditor';
lEditor.className = 'hidden';
var lFM = document.getElementById('fm');
if(lFM){
lFM.appendChild(lEditor);
CodeMirror(lEditor,{
mode : "xml",
htmlMode : true,
theme : 'night',
lineNumbers : true,
//переносим длинные строки
lineWrapping: true,
extraKeys: {
//Сохранение
"Esc": pParent.hide(pParent)
}
});
}else console.log('Error. Something went wrong FM not found');
}
};
};
/* function loads css files
* of CodeMirror
*/
var loadAll = function(pParent) {
return function(){
CloudCommander.cssLoad({
src : 'http://codemirror.net/lib/codemirror.css'
CloudCommander.Editor.CodeMirror = new CloudCommander.Util();
/* indicator says CodeMirror still loads */
CloudCommander.Editor.CodeMirror.loading = false;
/* function loads CodeMirror js and css files */
CloudCommander.Editor.CodeMirror.load = (function(pParent){
/* function shows editor */
var createEditorDiv = function(){
if (!pParent.getById('CloudEditor')) {
var lFM = document.getElementById('fm');
if(lFM)
pParent.anyload({
name : 'div',
id : 'CloudEditor',
element : lFM
});
CloudCommander.cssLoad({
src : 'http://codemirror.net/theme/night.css'
});
CloudCommander.cssSet({id:'editor',
inner : '.CodeMirror{' +
'font-family:\'Droid Sans Mono\';' +
'font-size:15px;' +
'resize:vertical;' +
'padding:20px;' +
'}' +
'.CodeMirror-scroll{' +
'height: 660px;' +
'}' +
'.CodeMirror-scrollbar{' +
'overflow-y:auto' +
'}'
});
CloudCommander.jsload('http://codemirror.net/mode/xml/xml.js',
showEditor(pParent));
};
else
console.log('Error. Something went wrong FM not found');
pParent.show();
}
};
/* function loads css files
* of CodeMirror
*/
var loadAll = function(pParent) {
return function(){
pParent.cssLoad({
src : 'lib/client/editor/codemirror/pack/codemirror.pack.css'
});
pParent.cssLoad({
src : 'lib/client/editor/codemirror/pack/night.pack.css'
});
pParent.cssSet({id:'editor',
inner : '.CodeMirror{' +
'font-family :\'Droid Sans Mono\';' +
'font-size :15px;' +
'padding :20px;' +
'}' +
'.CodeMirror-scroll{' +
'height : 660px;' +
'}'
});
pParent.jsload('lib/client/editor/' +
'codemirror/pack/javascript.pack.js',
createEditorDiv);
};
/* load CodeMirror main module */
CloudCommander.jsload('http://codemirror.net/lib/codemirror.js', loadAll(this));
}),
};
show : (function(){ /* function shows CodeMirror editor */
/* if CloudEditor is not loaded - loading him */
document.getElementById('CloudEditor') ||
this.load();
/* removing keyBinding if set */
CloudCommander.keyBinded = false;
/* load CodeMirror main module */
pParent.jsload('lib/client/editor/' +
'codemirror/pack/codemirror.pack.js',
loadAll(this));
});
/* function shows CodeMirror editor */
CloudCommander.Editor.CodeMirror.show = (function(){
/* if CloudEditor is not loaded - loading him */
if(!this.getById('CloudEditor'))
return this.load(this);
/* if CodeMirror function show already
* called do not call it again
* if f4 key pressed couple times
*/
if(this.loading)
return;
var lLeft = this.getById('left');
var lCloudEditor = this.getById('CloudEditor');
lLeft &&
(lLeft.className = 'panel hidden');
/* when folder view
* is no need to edit
* data
*/
var lReadOnly = false;
var lParent = this;
var initCodeMirror_f = function(pValue){
CodeMirror(lCloudEditor,{
mode : 'javascript',
value : pValue,
theme : 'night',
lineNumbers : true,
//переносим длинные строки
lineWrapping: false,
autofocus : true,
extraKeys: {
//Сохранение
"Esc": lParent.hide(lParent)
},
readOnly : lReadOnly
});
};
var lCloudEditor = this.getById('CloudEditor');
var lCurrent = this.getCurrentFile();
var lA;
/* getting link */
lA = lCurrent.getElementsByTagName('a');
if(!lA.length)
return console.log('Error:' +
'can not find links in current file');
lA = lA[0].href;
lCloudEditor &&
(lCloudEditor.className = '');
}),
hide : (function(pParent) {
return function(){
CloudCommander.keyBinded = true;
var lLeft = pParent.getById('left');
var lCloudEditor = pParent.getById('CloudEditor');
lCloudEditor &&
(lCloudEditor.className = 'hidden');
lLeft &&
(lLeft.className = 'panel');
};
}),
getById: function(pId){return document.getElementById(pId);},
/* убираем адрес хоста*/
lA = '/' + lA.replace(document.location.href,'');
getPanel: function(){
var lCurrent = document.getElementsByClassName('current-file');
lCurrent.length &&
(lCurrent = lCurrent[0].parentElement);
/* checking is this link is to directory */
var lSize = lCurrent.getElementsByClassName('size');
if(lSize){
lSize = lSize[0].textContent;
return lCurrent && lCurrent.id;
/* if directory - load json
* not html data
*/
if (lSize === '<dir>'){
if (lA.indexOf(CloudFunc.NOJS) ===
CloudFunc.FS.length) {
lA = lA.replace(CloudFunc.NOJS, '');
lReadOnly = true;
}
}
}
};
this.loading = true;
/* reading data from current file */
$.ajax({
url:lA,
error: (function(jqXHR, textStatus, errorThrown){
lParent.loading = false;
return lParent.Images.showError(jqXHR, textStatus, errorThrown);
}),
success:function(data, textStatus, jqXHR){
/* if we got json - show it */
if(typeof data === 'object')
data = JSON.stringify(data, null, 4);
initCodeMirror_f(data);
/* removing keyBinding if set */
CloudCommander.keyBinded = false;
lParent.hidePanel();
lParent.Images.hideLoad();
lParent.loading = false;
}
});
});
/* function hides CodeMirror editor */
CloudCommander.Editor.CodeMirror.hide = (function(pParent) {
return function(){
CloudCommander.keyBinded = true;
pParent.showPanel();
var lCloudEditor = pParent.getById('CloudEditor');
var lCodeMirror = pParent.getByClass('CodeMirror');
if(lCodeMirror.length)
lCloudEditor
.removeChild(lCodeMirror[0]);
};
});
CloudCommander.Editor.Keys = (function(){
"use strict";
/* loading js and css of CodeMirror */
CloudCommander.Editor.CodeMirror.load();
this.CodeMirror.show(this.CodeMirror);
var key_event=function(event){
@ -134,7 +198,4 @@ CloudCommander.Editor.Keys = (function(){
else
document.onkeypress=key_event;
/* клавиши назначены*/
CloudCommander.keyBinded=true;
});

View file

@ -0,0 +1,169 @@
.CodeMirror {
line-height: 1em;
font-family: monospace;
/* Necessary so the scrollbar can be absolutely positioned within the wrapper on Lion. */
position: relative;
/* This prevents unwanted scrollbars from showing up on the body and wrapper in IE. */
overflow: hidden;
}
.CodeMirror-scroll {
overflow-x: auto;
overflow-y: hidden;
height: 300px;
/* This is needed to prevent an IE[67] bug where the scrolled content
is visible outside of the scrolling box. */
position: relative;
outline: none;
}
/* Vertical scrollbar */
.CodeMirror-scrollbar {
float: right;
overflow-x: hidden;
overflow-y: scroll;
/* This corrects for the 1px gap introduced to the left of the scrollbar
by the rule for .CodeMirror-scrollbar-inner. */
margin-left: -1px;
}
.CodeMirror-scrollbar-inner {
/* This needs to have a nonzero width in order for the scrollbar to appear
in Firefox and IE9. */
width: 1px;
}
.CodeMirror-scrollbar.cm-sb-overlap {
/* Ensure that the scrollbar appears in Lion, and that it overlaps the content
rather than sitting to the right of it. */
position: absolute;
z-index: 1;
float: none;
right: 0;
min-width: 12px;
}
.CodeMirror-scrollbar.cm-sb-nonoverlap {
min-width: 12px;
}
.CodeMirror-scrollbar.cm-sb-ie7 {
min-width: 18px;
}
.CodeMirror-gutter {
position: absolute; left: 0; top: 0;
z-index: 10;
background-color: #f7f7f7;
border-right: 1px solid #eee;
min-width: 2em;
height: 100%;
}
.CodeMirror-gutter-text {
color: #aaa;
text-align: right;
padding: .4em .2em .4em .4em;
white-space: pre !important;
cursor: default;
}
.CodeMirror-lines {
padding: .4em;
white-space: pre;
cursor: text;
}
.CodeMirror-lines * {
/* Necessary for throw-scrolling to decelerate properly on Safari. */
pointer-events: none;
}
.CodeMirror pre {
-moz-border-radius: 0;
-webkit-border-radius: 0;
-o-border-radius: 0;
border-radius: 0;
border-width: 0; margin: 0; padding: 0; background: transparent;
font-family: inherit;
font-size: inherit;
padding: 0; margin: 0;
white-space: pre;
word-wrap: normal;
line-height: inherit;
color: inherit;
}
.CodeMirror-wrap pre {
word-wrap: break-word;
white-space: pre-wrap;
word-break: normal;
}
.CodeMirror-wrap .CodeMirror-scroll {
overflow-x: hidden;
}
.CodeMirror textarea {
outline: none !important;
}
.CodeMirror pre.CodeMirror-cursor {
z-index: 10;
position: absolute;
visibility: hidden;
border-left: 1px solid black;
border-right: none;
width: 0;
}
.cm-keymap-fat-cursor pre.CodeMirror-cursor {
width: auto;
border: 0;
background: transparent;
background: rgba(0, 200, 0, .4);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#6600c800, endColorstr=#4c00c800);
}
/* Kludge to turn off filter in ie9+, which also accepts rgba */
.cm-keymap-fat-cursor pre.CodeMirror-cursor:not(#nonsense_id) {
filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
}
.CodeMirror pre.CodeMirror-cursor.CodeMirror-overwrite {}
.CodeMirror-focused pre.CodeMirror-cursor {
visibility: visible;
}
div.CodeMirror-selected { background: #d9d9d9; }
.CodeMirror-focused div.CodeMirror-selected { background: #d7d4f0; }
.CodeMirror-searching {
background: #ffa;
background: rgba(255, 255, 0, .4);
}
/* Default theme */
.cm-s-default span.cm-keyword {color: #708;}
.cm-s-default span.cm-atom {color: #219;}
.cm-s-default span.cm-number {color: #164;}
.cm-s-default span.cm-def {color: #00f;}
.cm-s-default span.cm-variable {color: black;}
.cm-s-default span.cm-variable-2 {color: #05a;}
.cm-s-default span.cm-variable-3 {color: #085;}
.cm-s-default span.cm-property {color: black;}
.cm-s-default span.cm-operator {color: black;}
.cm-s-default span.cm-comment {color: #a50;}
.cm-s-default span.cm-string {color: #a11;}
.cm-s-default span.cm-string-2 {color: #f50;}
.cm-s-default span.cm-meta {color: #555;}
.cm-s-default span.cm-error {color: #f00;}
.cm-s-default span.cm-qualifier {color: #555;}
.cm-s-default span.cm-builtin {color: #30a;}
.cm-s-default span.cm-bracket {color: #cc7;}
.cm-s-default span.cm-tag {color: #170;}
.cm-s-default span.cm-attribute {color: #00c;}
.cm-s-default span.cm-header {color: blue;}
.cm-s-default span.cm-quote {color: #090;}
.cm-s-default span.cm-hr {color: #999;}
.cm-s-default span.cm-link {color: #00c;}
span.cm-header, span.cm-strong {font-weight: bold;}
span.cm-em {font-style: italic;}
span.cm-emstrong {font-style: italic; font-weight: bold;}
span.cm-link {text-decoration: underline;}
div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;}
div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,361 @@
CodeMirror.defineMode("javascript", function(config, parserConfig) {
var indentUnit = config.indentUnit;
var jsonMode = parserConfig.json;
// Tokenizer
var keywords = function(){
function kw(type) {return {type: type, style: "keyword"};}
var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c");
var operator = kw("operator"), atom = {type: "atom", style: "atom"};
return {
"if": A, "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B,
"return": C, "break": C, "continue": C, "new": C, "delete": C, "throw": C,
"var": kw("var"), "const": kw("var"), "let": kw("var"),
"function": kw("function"), "catch": kw("catch"),
"for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": kw("default"),
"in": operator, "typeof": operator, "instanceof": operator,
"true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom, "Infinity": atom
};
}();
var isOperatorChar = /[+\-*&%=<>!?|]/;
function chain(stream, state, f) {
state.tokenize = f;
return f(stream, state);
}
function nextUntilUnescaped(stream, end) {
var escaped = false, next;
while ((next = stream.next()) != null) {
if (next == end && !escaped)
return false;
escaped = !escaped && next == "\\";
}
return escaped;
}
// Used as scratch variables to communicate multiple values without
// consing up tons of objects.
var type, content;
function ret(tp, style, cont) {
type = tp; content = cont;
return style;
}
function jsTokenBase(stream, state) {
var ch = stream.next();
if (ch == '"' || ch == "'")
return chain(stream, state, jsTokenString(ch));
else if (/[\[\]{}\(\),;\:\.]/.test(ch))
return ret(ch);
else if (ch == "0" && stream.eat(/x/i)) {
stream.eatWhile(/[\da-f]/i);
return ret("number", "number");
}
else if (/\d/.test(ch) || ch == "-" && stream.eat(/\d/)) {
stream.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/);
return ret("number", "number");
}
else if (ch == "/") {
if (stream.eat("*")) {
return chain(stream, state, jsTokenComment);
}
else if (stream.eat("/")) {
stream.skipToEnd();
return ret("comment", "comment");
}
else if (state.reAllowed) {
nextUntilUnescaped(stream, "/");
stream.eatWhile(/[gimy]/); // 'y' is "sticky" option in Mozilla
return ret("regexp", "string-2");
}
else {
stream.eatWhile(isOperatorChar);
return ret("operator", null, stream.current());
}
}
else if (ch == "#") {
stream.skipToEnd();
return ret("error", "error");
}
else if (isOperatorChar.test(ch)) {
stream.eatWhile(isOperatorChar);
return ret("operator", null, stream.current());
}
else {
stream.eatWhile(/[\w\$_]/);
var word = stream.current(), known = keywords.propertyIsEnumerable(word) && keywords[word];
return (known && state.kwAllowed) ? ret(known.type, known.style, word) :
ret("variable", "variable", word);
}
}
function jsTokenString(quote) {
return function(stream, state) {
if (!nextUntilUnescaped(stream, quote))
state.tokenize = jsTokenBase;
return ret("string", "string");
};
}
function jsTokenComment(stream, state) {
var maybeEnd = false, ch;
while (ch = stream.next()) {
if (ch == "/" && maybeEnd) {
state.tokenize = jsTokenBase;
break;
}
maybeEnd = (ch == "*");
}
return ret("comment", "comment");
}
// Parser
var atomicTypes = {"atom": true, "number": true, "variable": true, "string": true, "regexp": true};
function JSLexical(indented, column, type, align, prev, info) {
this.indented = indented;
this.column = column;
this.type = type;
this.prev = prev;
this.info = info;
if (align != null) this.align = align;
}
function inScope(state, varname) {
for (var v = state.localVars; v; v = v.next)
if (v.name == varname) return true;
}
function parseJS(state, style, type, content, stream) {
var cc = state.cc;
// Communicate our context to the combinators.
// (Less wasteful than consing up a hundred closures on every call.)
cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc;
if (!state.lexical.hasOwnProperty("align"))
state.lexical.align = true;
while(true) {
var combinator = cc.length ? cc.pop() : jsonMode ? expression : statement;
if (combinator(type, content)) {
while(cc.length && cc[cc.length - 1].lex)
cc.pop()();
if (cx.marked) return cx.marked;
if (type == "variable" && inScope(state, content)) return "variable-2";
return style;
}
}
}
// Combinator utils
var cx = {state: null, column: null, marked: null, cc: null};
function pass() {
for (var i = arguments.length - 1; i >= 0; i--) cx.cc.push(arguments[i]);
}
function cont() {
pass.apply(null, arguments);
return true;
}
function register(varname) {
var state = cx.state;
if (state.context) {
cx.marked = "def";
for (var v = state.localVars; v; v = v.next)
if (v.name == varname) return;
state.localVars = {name: varname, next: state.localVars};
}
}
// Combinators
var defaultVars = {name: "this", next: {name: "arguments"}};
function pushcontext() {
if (!cx.state.context) cx.state.localVars = defaultVars;
cx.state.context = {prev: cx.state.context, vars: cx.state.localVars};
}
function popcontext() {
cx.state.localVars = cx.state.context.vars;
cx.state.context = cx.state.context.prev;
}
function pushlex(type, info) {
var result = function() {
var state = cx.state;
state.lexical = new JSLexical(state.indented, cx.stream.column(), type, null, state.lexical, info);
};
result.lex = true;
return result;
}
function poplex() {
var state = cx.state;
if (state.lexical.prev) {
if (state.lexical.type == ")")
state.indented = state.lexical.indented;
state.lexical = state.lexical.prev;
}
}
poplex.lex = true;
function expect(wanted) {
return function expecting(type) {
if (type == wanted) return cont();
else if (wanted == ";") return pass();
else return cont(arguments.callee);
};
}
function statement(type) {
if (type == "var") return cont(pushlex("vardef"), vardef1, expect(";"), poplex);
if (type == "keyword a") return cont(pushlex("form"), expression, statement, poplex);
if (type == "keyword b") return cont(pushlex("form"), statement, poplex);
if (type == "{") return cont(pushlex("}"), block, poplex);
if (type == ";") return cont();
if (type == "function") return cont(functiondef);
if (type == "for") return cont(pushlex("form"), expect("("), pushlex(")"), forspec1, expect(")"),
poplex, statement, poplex);
if (type == "variable") return cont(pushlex("stat"), maybelabel);
if (type == "switch") return cont(pushlex("form"), expression, pushlex("}", "switch"), expect("{"),
block, poplex, poplex);
if (type == "case") return cont(expression, expect(":"));
if (type == "default") return cont(expect(":"));
if (type == "catch") return cont(pushlex("form"), pushcontext, expect("("), funarg, expect(")"),
statement, poplex, popcontext);
return pass(pushlex("stat"), expression, expect(";"), poplex);
}
function expression(type) {
if (atomicTypes.hasOwnProperty(type)) return cont(maybeoperator);
if (type == "function") return cont(functiondef);
if (type == "keyword c") return cont(maybeexpression);
if (type == "(") return cont(pushlex(")"), maybeexpression, expect(")"), poplex, maybeoperator);
if (type == "operator") return cont(expression);
if (type == "[") return cont(pushlex("]"), commasep(expression, "]"), poplex, maybeoperator);
if (type == "{") return cont(pushlex("}"), commasep(objprop, "}"), poplex, maybeoperator);
return cont();
}
function maybeexpression(type) {
if (type.match(/[;\}\)\],]/)) return pass();
return pass(expression);
}
function maybeoperator(type, value) {
if (type == "operator" && /\+\+|--/.test(value)) return cont(maybeoperator);
if (type == "operator" || type == ":") return cont(expression);
if (type == ";") return;
if (type == "(") return cont(pushlex(")"), commasep(expression, ")"), poplex, maybeoperator);
if (type == ".") return cont(property, maybeoperator);
if (type == "[") return cont(pushlex("]"), expression, expect("]"), poplex, maybeoperator);
}
function maybelabel(type) {
if (type == ":") return cont(poplex, statement);
return pass(maybeoperator, expect(";"), poplex);
}
function property(type) {
if (type == "variable") {cx.marked = "property"; return cont();}
}
function objprop(type) {
if (type == "variable") cx.marked = "property";
if (atomicTypes.hasOwnProperty(type)) return cont(expect(":"), expression);
}
function commasep(what, end) {
function proceed(type) {
if (type == ",") return cont(what, proceed);
if (type == end) return cont();
return cont(expect(end));
}
return function commaSeparated(type) {
if (type == end) return cont();
else return pass(what, proceed);
};
}
function block(type) {
if (type == "}") return cont();
return pass(statement, block);
}
function vardef1(type, value) {
if (type == "variable"){register(value); return cont(vardef2);}
return cont();
}
function vardef2(type, value) {
if (value == "=") return cont(expression, vardef2);
if (type == ",") return cont(vardef1);
}
function forspec1(type) {
if (type == "var") return cont(vardef1, forspec2);
if (type == ";") return pass(forspec2);
if (type == "variable") return cont(formaybein);
return pass(forspec2);
}
function formaybein(type, value) {
if (value == "in") return cont(expression);
return cont(maybeoperator, forspec2);
}
function forspec2(type, value) {
if (type == ";") return cont(forspec3);
if (value == "in") return cont(expression);
return cont(expression, expect(";"), forspec3);
}
function forspec3(type) {
if (type != ")") cont(expression);
}
function functiondef(type, value) {
if (type == "variable") {register(value); return cont(functiondef);}
if (type == "(") return cont(pushlex(")"), pushcontext, commasep(funarg, ")"), poplex, statement, popcontext);
}
function funarg(type, value) {
if (type == "variable") {register(value); return cont();}
}
// Interface
return {
startState: function(basecolumn) {
return {
tokenize: jsTokenBase,
reAllowed: true,
kwAllowed: true,
cc: [],
lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false),
localVars: parserConfig.localVars,
context: parserConfig.localVars && {vars: parserConfig.localVars},
indented: 0
};
},
token: function(stream, state) {
if (stream.sol()) {
if (!state.lexical.hasOwnProperty("align"))
state.lexical.align = false;
state.indented = stream.indentation();
}
if (stream.eatSpace()) return null;
var style = state.tokenize(stream, state);
if (type == "comment") return style;
state.reAllowed = !!(type == "operator" || type == "keyword c" || type.match(/^[\[{}\(,;:]$/));
state.kwAllowed = type != '.';
return parseJS(state, style, type, content, stream);
},
indent: function(state, textAfter) {
if (state.tokenize != jsTokenBase) return 0;
var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical;
if (lexical.type == "stat" && firstChar == "}") lexical = lexical.prev;
var type = lexical.type, closing = firstChar == type;
if (type == "vardef") return lexical.indented + 4;
else if (type == "form" && firstChar == "{") return lexical.indented;
else if (type == "stat" || type == "form") return lexical.indented + indentUnit;
else if (lexical.info == "switch" && !closing)
return lexical.indented + (/^(?:case|default)\b/.test(textAfter) ? indentUnit : 2 * indentUnit);
else if (lexical.align) return lexical.column + (closing ? 0 : 1);
else return lexical.indented + (closing ? 0 : indentUnit);
},
electricChars: ":{}"
};
});
CodeMirror.defineMIME("text/javascript", "javascript");
CodeMirror.defineMIME("application/json", {name: "javascript", json: true});

326
lib/client/editor/codemirror/mode/xml.js vendored Normal file
View file

@ -0,0 +1,326 @@
CodeMirror.defineMode("xml", function(config, parserConfig) {
var indentUnit = config.indentUnit;
var Kludges = parserConfig.htmlMode ? {
autoSelfClosers: {'area': true, 'base': true, 'br': true, 'col': true, 'command': true,
'embed': true, 'frame': true, 'hr': true, 'img': true, 'input': true,
'keygen': true, 'link': true, 'meta': true, 'param': true, 'source': true,
'track': true, 'wbr': true},
implicitlyClosed: {'dd': true, 'li': true, 'optgroup': true, 'option': true, 'p': true,
'rp': true, 'rt': true, 'tbody': true, 'td': true, 'tfoot': true,
'th': true, 'tr': true},
contextGrabbers: {
'dd': {'dd': true, 'dt': true},
'dt': {'dd': true, 'dt': true},
'li': {'li': true},
'option': {'option': true, 'optgroup': true},
'optgroup': {'optgroup': true},
'p': {'address': true, 'article': true, 'aside': true, 'blockquote': true, 'dir': true,
'div': true, 'dl': true, 'fieldset': true, 'footer': true, 'form': true,
'h1': true, 'h2': true, 'h3': true, 'h4': true, 'h5': true, 'h6': true,
'header': true, 'hgroup': true, 'hr': true, 'menu': true, 'nav': true, 'ol': true,
'p': true, 'pre': true, 'section': true, 'table': true, 'ul': true},
'rp': {'rp': true, 'rt': true},
'rt': {'rp': true, 'rt': true},
'tbody': {'tbody': true, 'tfoot': true},
'td': {'td': true, 'th': true},
'tfoot': {'tbody': true},
'th': {'td': true, 'th': true},
'thead': {'tbody': true, 'tfoot': true},
'tr': {'tr': true}
},
doNotIndent: {"pre": true},
allowUnquoted: true,
allowMissing: false
} : {
autoSelfClosers: {},
implicitlyClosed: {},
contextGrabbers: {},
doNotIndent: {},
allowUnquoted: false,
allowMissing: false
};
var alignCDATA = parserConfig.alignCDATA;
// Return variables for tokenizers
var tagName, type;
function inText(stream, state) {
function chain(parser) {
state.tokenize = parser;
return parser(stream, state);
}
var ch = stream.next();
if (ch == "<") {
if (stream.eat("!")) {
if (stream.eat("[")) {
if (stream.match("CDATA[")) return chain(inBlock("atom", "]]>"));
else return null;
}
else if (stream.match("--")) return chain(inBlock("comment", "-->"));
else if (stream.match("DOCTYPE", true, true)) {
stream.eatWhile(/[\w\._\-]/);
return chain(doctype(1));
}
else return null;
}
else if (stream.eat("?")) {
stream.eatWhile(/[\w\._\-]/);
state.tokenize = inBlock("meta", "?>");
return "meta";
}
else {
type = stream.eat("/") ? "closeTag" : "openTag";
stream.eatSpace();
tagName = "";
var c;
while ((c = stream.eat(/[^\s\u00a0=<>\"\'\/?]/))) tagName += c;
state.tokenize = inTag;
return "tag";
}
}
else if (ch == "&") {
var ok;
if (stream.eat("#")) {
if (stream.eat("x")) {
ok = stream.eatWhile(/[a-fA-F\d]/) && stream.eat(";");
} else {
ok = stream.eatWhile(/[\d]/) && stream.eat(";");
}
} else {
ok = stream.eatWhile(/[\w\.\-:]/) && stream.eat(";");
}
return ok ? "atom" : "error";
}
else {
stream.eatWhile(/[^&<]/);
return null;
}
}
function inTag(stream, state) {
var ch = stream.next();
if (ch == ">" || (ch == "/" && stream.eat(">"))) {
state.tokenize = inText;
type = ch == ">" ? "endTag" : "selfcloseTag";
return "tag";
}
else if (ch == "=") {
type = "equals";
return null;
}
else if (/[\'\"]/.test(ch)) {
state.tokenize = inAttribute(ch);
return state.tokenize(stream, state);
}
else {
stream.eatWhile(/[^\s\u00a0=<>\"\'\/?]/);
return "word";
}
}
function inAttribute(quote) {
return function(stream, state) {
while (!stream.eol()) {
if (stream.next() == quote) {
state.tokenize = inTag;
break;
}
}
return "string";
};
}
function inBlock(style, terminator) {
return function(stream, state) {
while (!stream.eol()) {
if (stream.match(terminator)) {
state.tokenize = inText;
break;
}
stream.next();
}
return style;
};
}
function doctype(depth) {
return function(stream, state) {
var ch;
while ((ch = stream.next()) != null) {
if (ch == "<") {
state.tokenize = doctype(depth + 1);
return state.tokenize(stream, state);
} else if (ch == ">") {
if (depth == 1) {
state.tokenize = inText;
break;
} else {
state.tokenize = doctype(depth - 1);
return state.tokenize(stream, state);
}
}
}
return "meta";
};
}
var curState, setStyle;
function pass() {
for (var i = arguments.length - 1; i >= 0; i--) curState.cc.push(arguments[i]);
}
function cont() {
pass.apply(null, arguments);
return true;
}
function pushContext(tagName, startOfLine) {
var noIndent = Kludges.doNotIndent.hasOwnProperty(tagName) || (curState.context && curState.context.noIndent);
curState.context = {
prev: curState.context,
tagName: tagName,
indent: curState.indented,
startOfLine: startOfLine,
noIndent: noIndent
};
}
function popContext() {
if (curState.context) curState.context = curState.context.prev;
}
function element(type) {
if (type == "openTag") {
curState.tagName = tagName;
return cont(attributes, endtag(curState.startOfLine));
} else if (type == "closeTag") {
var err = false;
if (curState.context) {
if (curState.context.tagName != tagName) {
if (Kludges.implicitlyClosed.hasOwnProperty(curState.context.tagName.toLowerCase())) {
popContext();
}
err = !curState.context || curState.context.tagName != tagName;
}
} else {
err = true;
}
if (err) setStyle = "error";
return cont(endclosetag(err));
}
return cont();
}
function endtag(startOfLine) {
return function(type) {
if (type == "selfcloseTag" ||
(type == "endTag" && Kludges.autoSelfClosers.hasOwnProperty(curState.tagName.toLowerCase()))) {
maybePopContext(curState.tagName.toLowerCase());
return cont();
}
if (type == "endTag") {
maybePopContext(curState.tagName.toLowerCase());
pushContext(curState.tagName, startOfLine);
return cont();
}
return cont();
};
}
function endclosetag(err) {
return function(type) {
if (err) setStyle = "error";
if (type == "endTag") { popContext(); return cont(); }
setStyle = "error";
return cont(arguments.callee);
}
}
function maybePopContext(nextTagName) {
var parentTagName;
while (true) {
if (!curState.context) {
return;
}
parentTagName = curState.context.tagName.toLowerCase();
if (!Kludges.contextGrabbers.hasOwnProperty(parentTagName) ||
!Kludges.contextGrabbers[parentTagName].hasOwnProperty(nextTagName)) {
return;
}
popContext();
}
}
function attributes(type) {
if (type == "word") {setStyle = "attribute"; return cont(attribute, attributes);}
if (type == "endTag" || type == "selfcloseTag") return pass();
setStyle = "error";
return cont(attributes);
}
function attribute(type) {
if (type == "equals") return cont(attvalue, attributes);
if (!Kludges.allowMissing) setStyle = "error";
return (type == "endTag" || type == "selfcloseTag") ? pass() : cont();
}
function attvalue(type) {
if (type == "string") return cont(attvaluemaybe);
if (type == "word" && Kludges.allowUnquoted) {setStyle = "string"; return cont();}
setStyle = "error";
return (type == "endTag" || type == "selfCloseTag") ? pass() : cont();
}
function attvaluemaybe(type) {
if (type == "string") return cont(attvaluemaybe);
else return pass();
}
return {
startState: function() {
return {tokenize: inText, cc: [], indented: 0, startOfLine: true, tagName: null, context: null};
},
token: function(stream, state) {
if (stream.sol()) {
state.startOfLine = true;
state.indented = stream.indentation();
}
if (stream.eatSpace()) return null;
setStyle = type = tagName = null;
var style = state.tokenize(stream, state);
state.type = type;
if ((style || type) && style != "comment") {
curState = state;
while (true) {
var comb = state.cc.pop() || element;
if (comb(type || style)) break;
}
}
state.startOfLine = false;
return setStyle || style;
},
indent: function(state, textAfter, fullLine) {
var context = state.context;
if ((state.tokenize != inTag && state.tokenize != inText) ||
context && context.noIndent)
return fullLine ? fullLine.match(/^(\s*)/)[0].length : 0;
if (alignCDATA && /<!\[CDATA\[/.test(textAfter)) return 0;
if (context && /^<\//.test(textAfter))
context = context.prev;
while (context && !context.startOfLine)
context = context.prev;
if (context) return context.indent + indentUnit;
else return 0;
},
compareStates: function(a, b) {
if (a.indented != b.indented || a.tokenize != b.tokenize) return false;
for (var ca = a.context, cb = b.context; ; ca = ca.prev, cb = cb.prev) {
if (!ca || !cb) return ca == cb;
if (ca.tagName != cb.tagName || ca.indent != cb.indent) return false;
}
},
electricChars: "/"
};
});
CodeMirror.defineMIME("text/xml", "xml");
CodeMirror.defineMIME("application/xml", "xml");
if (!CodeMirror.mimeModes.hasOwnProperty("text/html"))
CodeMirror.defineMIME("text/html", {name: "xml", htmlMode: true});

View file

@ -0,0 +1 @@
.CodeMirror{line-height:1em;font-family:monospace;position:relative;overflow:hidden}.CodeMirror-scroll{overflow-x:auto;overflow-y:hidden;height:300px;position:relative;outline:0}.CodeMirror-scrollbar{float:right;overflow-x:hidden;overflow-y:scroll;margin-left:-1px}.CodeMirror-scrollbar-inner{width:1px}.CodeMirror-scrollbar.cm-sb-overlap{position:absolute;z-index:1;float:none;right:0;min-width:12px}.CodeMirror-scrollbar.cm-sb-nonoverlap{min-width:12px}.CodeMirror-scrollbar.cm-sb-ie7{min-width:18px}.CodeMirror-gutter{position:absolute;left:0;top:0;z-index:10;background-color:#f7f7f7;border-right:1px solid #eee;min-width:2em;height:100%}.CodeMirror-gutter-text{color:#aaa;text-align:right;padding:.4em .2em .4em .4em;white-space:pre!important;cursor:default}.CodeMirror-lines{padding:.4em;white-space:pre;cursor:text}.CodeMirror-lines *{pointer-events:none}.CodeMirror pre{-moz-border-radius:0;-webkit-border-radius:0;-o-border-radius:0;border-radius:0;border-width:0;margin:0;padding:0;background:transparent;font-family:inherit;font-size:inherit;padding:0;margin:0;white-space:pre;word-wrap:normal;line-height:inherit;color:inherit}.CodeMirror-wrap pre{word-wrap:break-word;white-space:pre-wrap;word-break:normal}.CodeMirror-wrap .CodeMirror-scroll{overflow-x:hidden}.CodeMirror textarea{outline:0!important}.CodeMirror pre.CodeMirror-cursor{z-index:10;position:absolute;visibility:hidden;border-left:1px solid black;border-right:0;width:0}.cm-keymap-fat-cursor pre.CodeMirror-cursor{width:auto;border:0;background:transparent;background:rgba(0,200,0,.4);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#6600c800, endColorstr=#4c00c800)}.cm-keymap-fat-cursor pre.CodeMirror-cursor:not(#nonsense_id){filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.CodeMirror pre.CodeMirror-cursor.CodeMirror-overwrite{}.CodeMirror-focused pre.CodeMirror-cursor{visibility:visible}div.CodeMirror-selected{background:#d9d9d9}.CodeMirror-focused div.CodeMirror-selected{background:#d7d4f0}.CodeMirror-searching{background:#ffa;background:rgba(255,255,0,.4)}.cm-s-default span.cm-keyword{color:#708}.cm-s-default span.cm-atom{color:#219}.cm-s-default span.cm-number{color:#164}.cm-s-default span.cm-def{color:#00f}.cm-s-default span.cm-variable{color:#000}.cm-s-default span.cm-variable-2{color:#05a}.cm-s-default span.cm-variable-3{color:#085}.cm-s-default span.cm-property{color:#000}.cm-s-default span.cm-operator{color:#000}.cm-s-default span.cm-comment{color:#a50}.cm-s-default span.cm-string{color:#a11}.cm-s-default span.cm-string-2{color:#f50}.cm-s-default span.cm-meta{color:#555}.cm-s-default span.cm-error{color:red}.cm-s-default span.cm-qualifier{color:#555}.cm-s-default span.cm-builtin{color:#30a}.cm-s-default span.cm-bracket{color:#cc7}.cm-s-default span.cm-tag{color:#170}.cm-s-default span.cm-attribute{color:#00c}.cm-s-default span.cm-header{color:blue}.cm-s-default span.cm-quote{color:#090}.cm-s-default span.cm-hr{color:#999}.cm-s-default span.cm-link{color:#00c}span.cm-header,span.cm-strong{font-weight:700}span.cm-em{font-style:italic}span.cm-emstrong{font-style:italic;font-weight:700}span.cm-link{text-decoration:underline}div.CodeMirror span.CodeMirror-matchingbracket{color:#0f0}div.CodeMirror span.CodeMirror-nonmatchingbracket{color:#f22}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1 @@
.cm-s-night{background:#0a001f;color:#f8f8f8}.cm-s-night div.CodeMirror-selected{background:#447!important}.cm-s-night .CodeMirror-gutter{background:#0a001f;border-right:1px solid #aaa}.cm-s-night .CodeMirror-gutter-text{color:#f8f8f8}.cm-s-night .CodeMirror-cursor{border-left:1px solid white!important}.cm-s-night span.cm-comment{color:#6900a1}.cm-s-night span.cm-atom{color:#845dc4}.cm-s-night span.cm-number,.cm-s-night span.cm-attribute{color:#ffd500}.cm-s-night span.cm-keyword{color:#599eff}.cm-s-night span.cm-string{color:#37f14a}.cm-s-night span.cm-meta{color:#7678e2}.cm-s-night span.cm-variable-2,.cm-s-night span.cm-tag{color:#99b2ff}.cm-s-night span.cm-variable-3,.cm-s-night span.cm-def{color:#fff}.cm-s-night span.cm-error{color:#9d1e15}.cm-s-night span.cm-bracket{color:#8da6ce}.cm-s-night span.cm-comment{color:#6900a1}.cm-s-night span.cm-builtin,.cm-s-night span.cm-special{color:#ff9e59}.cm-s-night span.cm-link{color:#845dc4}

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,21 @@
/* Loosely based on the Midnight Textmate theme */
.cm-s-night { background: #0a001f; color: #f8f8f8; }
.cm-s-night div.CodeMirror-selected { background: #447 !important; }
.cm-s-night .CodeMirror-gutter { background: #0a001f; border-right: 1px solid #aaa; }
.cm-s-night .CodeMirror-gutter-text { color: #f8f8f8; }
.cm-s-night .CodeMirror-cursor { border-left: 1px solid white !important; }
.cm-s-night span.cm-comment { color: #6900a1; }
.cm-s-night span.cm-atom { color: #845dc4; }
.cm-s-night span.cm-number, .cm-s-night span.cm-attribute { color: #ffd500; }
.cm-s-night span.cm-keyword { color: #599eff; }
.cm-s-night span.cm-string { color: #37f14a; }
.cm-s-night span.cm-meta { color: #7678e2; }
.cm-s-night span.cm-variable-2, .cm-s-night span.cm-tag { color: #99b2ff; }
.cm-s-night span.cm-variable-3, .cm-s-night span.cm-def { color: white; }
.cm-s-night span.cm-error { color: #9d1e15; }
.cm-s-night span.cm-bracket { color: #8da6ce; }
.cm-s-night span.cm-comment { color: #6900a1; }
.cm-s-night span.cm-builtin, .cm-s-night span.cm-special { color: #ff9e59; }
.cm-s-night span.cm-link { color: #845dc4; }

View file

@ -1,248 +1,283 @@
var CloudCommander;
var CloudFunc;
CloudCommander.keyBinding=(function(){
"use strict";
var key_event=function(event){
var lCurrentFile;
var lName, lTop;
/* если клавиши можно обрабатывать*/
if(CloudCommander.keyBinded){
/* если нажали таб:
* переносим курсор на
* правую панель, если
* мы были на левой и
* наоборот
*/
if(event.keyCode===9){
console.log('Tab pressed');
try{
lCurrentFile=document.getElementsByClassName(CloudCommander.CURRENT_FILE)[0];
}catch(error){console.log(error);}
}
/* навигация по таблице файлов*/
/* если нажали клавишу вверх*/
else if(event.keyCode===38){
/* получаем выдленный файл*/
lCurrentFile=document.getElementsByClassName(CloudCommander.CURRENT_FILE);
/* если ненайдены выделенные файлы - выходим*/
if(lCurrentFile.length===0)return;
lCurrentFile=lCurrentFile[0];
/* если это строка существет и
* если она не заголовок
* файловой таблицы
*/
if(lCurrentFile.previousSibling &&
lCurrentFile.previousSibling.className!=='fm_header' ){
/* убираем выделение с текущего элемента */
lCurrentFile.className='';
/* и выделяем предыдущую строку*/
lCurrentFile.previousSibling.className = CloudCommander.CURRENT_FILE;
/* if we on the top of
* the screan then
* moving down the scroolbar
*/
lTop = lCurrentFile.previousSibling.offsetTop;
lTop %
(CloudCommander.HEIGHT -
CloudCommander.HEIGHT/10) < 70 &&
lCurrentFile.parentElement.scrollByLines(-2);
event.preventDefault();
}
}
/* если нажали клавишу в низ*/
else if(event.keyCode===40){
/* получаем выдленный файл*/
lCurrentFile=document.getElementsByClassName(CloudCommander.CURRENT_FILE);
/* если ненайдены выделенные файлы - выходим*/
if(lCurrentFile.length===0)return;
lCurrentFile=lCurrentFile[0];
/* если это не последняя строка */
if(lCurrentFile.nextSibling){
/* убираем с него выделение */
lCurrentFile.className='';
/* выделяем следующую строку*/
lCurrentFile.nextSibling.className = CloudCommander.CURRENT_FILE;
/* if we on the bottom of
* the screan then
* moving down the scroolbar
*/
lTop = lCurrentFile.previousSibling.offsetTop;
var lHeight = CloudCommander.HEIGHT;
var lMod = lTop % (lHeight - lHeight/10) < 70;
lTop > (lHeight/10) &&
lMod < 70 && lMod > 50 &&
console.log(lCurrentFile
.parentElement
.scrollByLines(2) || '!');
event.preventDefault();
}
}
/* если нажали клавишу page up или Home
* переходим к самому верхнему
* элементу
*/
else if(/*event.keyCode===33 ||*/ event.keyCode===36){
lCurrentFile=document.getElementsByClassName(CloudCommander.CURRENT_FILE)[0];
/* убираем выделение с текущего файла*/
lCurrentFile.className='';
/* получаем первый элемент*/
lCurrentFile.parentElement.firstElementChild
/* пропускаем путь и заголовки столбиков*/
.nextElementSibling.nextElementSibling
/* выделяем верхий файл */
.className=CloudCommander.CURRENT_FILE;
}
/* если нажали клавишу page down или End
* выделяем последний элемент
*/
else if(/*event.keyCode===34 ||*/ event.keyCode===35){
lCurrentFile=document.getElementsByClassName(CloudCommander.CURRENT_FILE)[0];
/* снимаем выделение с текущего файла*/
lCurrentFile.className='';
/* выделяем самый нижний файл */
lCurrentFile.parentElement.lastElementChild.className=CloudCommander.CURRENT_FILE;
}
/* если нажали Enter - открываем папку*/
else if(event.keyCode===13){
lCurrentFile=document.getElementsByClassName(CloudCommander.CURRENT_FILE);
/* если ненайдены выделенные файлы - выходим*/
if(!lCurrentFile.length)return;
lCurrentFile=lCurrentFile[0];
/* из него достаём спан с именем файла*/
lName=lCurrentFile.getElementsByClassName('name');
/* если нету (что вряд ли) - выходим*/
if(!lName)return false;
/* достаём все ссылки*/
var lATag=lName[0].getElementsByTagName('a');
/* если нету - выходим */
if(!lATag)return false;
/* вызываем 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(CloudCommander.CURRENT_FILE);
if(lCurrentFile.length>0)lCurrentFile=lCurrentFile[0];
/* получаем название файла*/
var lSelectedName=lCurrentFile.getElementsByTagName('a')[0].textContent;
/* если нашли элемент нажимаем него
* а если не можем - нажимаем на
* ссылку, на которую повешен 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++){
lName=lLi[i].getElementsByTagName('a')[0].textContent;
if(lSelectedName.length===lName.length &&
!lSelectedName.indexOf(lName)){
lLi[i].className=CloudCommander.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');
/* обработчик нажатий клавиш снят*/
CloudCommander.keyBinded=false;
}
}
/* если нажали <alt>+s
* устанавливаем все обработчики
* нажатий клавиш
*/
else if(event.keyCode===83 &&
event.altKey){
/*
document.addEventListener('keydown', key_event,false);
*/
/* обрабатываем нажатия на клавиши*/
CloudCommander.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;
/* клавиши назначены*/
CloudCommander.keyBinded=true;
var CloudCommander;
var CloudFunc;
CloudCommander.keyBinding=(function(){
"use strict";
var Util = new CloudCommander.Util();
var lTabPanel = {
left : 0,
right : 0
};
var key_event=function(event){
var lCurrentFile;
var lName, lTop;
/* если клавиши можно обрабатывать*/
if(CloudCommander.keyBinded){
/* если нажали таб:
* переносим курсор на
* правую панель, если
* мы были на левой и
* наоборот
*/
if(event.keyCode===9){
console.log('Tab pressed');
var lCURRENT_FILE = CloudCommander.CURRENT_FILE;
try{
lCurrentFile = Util.getByClass(lCURRENT_FILE)[0];
/* changing parent panel of curent-file */
var lId = lCurrentFile.parentElement.id;
lTabPanel[lId] = lCurrentFile;
lId = (lId === 'right')?
'left':'right';
if(lTabPanel[lId])
lTabPanel[lId].className = lCURRENT_FILE;
else
Util.getById(lId).getElementsByTagName('li')[2]
.className = lCURRENT_FILE;
lCurrentFile.className = '';
}catch(error){console.log(error);}
}
/* if f2 pressed */
else if(event.keyCode===113){
}
/* if f3 pressed */
else if(event.keyCode===114){
if (typeof CloudCommander.Viewer === 'function')
CloudCommander.Viewer();
}
/* if alt+f3 pressed */
else if(event.keyCode===114 &&
event.altKey){
if (typeof CloudCommander.Terminal === 'function')
CloudCommander.Terminal();
}
/* if f4 pressed */
else if(event.keyCode === 115) {
Util.Images.showLoad();
if (typeof CloudCommander.Editor === 'function')
CloudCommander.Editor();
}
/* навигация по таблице файлов*/
/* если нажали клавишу вверх*/
else if(event.keyCode===38){
/* получаем выдленный файл*/
lCurrentFile=Util.getByClass(CloudCommander.CURRENT_FILE);
/* если ненайдены выделенные файлы - выходим*/
if(lCurrentFile.length===0)return;
lCurrentFile=lCurrentFile[0];
/* если это строка существет и
* если она не заголовок
* файловой таблицы
*/
if(lCurrentFile.previousSibling &&
lCurrentFile.previousSibling.className!=='fm_header' ){
/* убираем выделение с текущего элемента */
lCurrentFile.className='';
/* и выделяем предыдущую строку*/
lCurrentFile.previousSibling.className = CloudCommander.CURRENT_FILE;
/* if we on the top of
* the screan then
* moving down the scroolbar
*/
lTop = lCurrentFile.previousSibling.offsetTop;
lTop %
(CloudCommander.HEIGHT -
CloudCommander.HEIGHT/10) < 70 &&
lCurrentFile.parentElement.scrollByLines(-2);
}
}
/* если нажали клавишу в низ*/
else if(event.keyCode===40){
/* получаем выдленный файл*/
lCurrentFile = Util.getByClass(CloudCommander.CURRENT_FILE);
/* если ненайдены выделенные файлы - выходим*/
if(lCurrentFile.length===0)return;
lCurrentFile=lCurrentFile[0];
/* если это не последняя строка */
if(lCurrentFile.nextSibling){
/* убираем с него выделение */
lCurrentFile.className='';
/* выделяем следующую строку*/
lCurrentFile.nextSibling.className = CloudCommander.CURRENT_FILE;
/* if we on the bottom of
* the screan then
* moving down the scroolbar
*/
lTop = lCurrentFile.previousSibling.offsetTop;
var lHeight = CloudCommander.HEIGHT;
var lMod = lTop % (lHeight - lHeight/10) < 70;
lTop > (lHeight/10) &&
lMod < 70 && lMod > 50 &&
console.log(lCurrentFile
.parentElement
.scrollByLines(2) || '!');
}
}
/* если нажали клавишу page up или Home
* переходим к самому верхнему
* элементу
*/
else if(/*event.keyCode===33 ||*/ event.keyCode===36){
lCurrentFile = Util.getByClass(CloudCommander.CURRENT_FILE)[0];
/* убираем выделение с текущего файла*/
lCurrentFile.className='';
/* получаем первый элемент*/
lCurrentFile.parentElement.firstElementChild
/* пропускаем путь и заголовки столбиков*/
.nextElementSibling.nextElementSibling
/* выделяем верхий файл */
.className=CloudCommander.CURRENT_FILE;
}
/* если нажали клавишу page down или End
* выделяем последний элемент
*/
else if(/*event.keyCode===34 ||*/ event.keyCode===35){
lCurrentFile = Util.getByClass(CloudCommander.CURRENT_FILE)[0];
/* снимаем выделение с текущего файла*/
lCurrentFile.className='';
/* выделяем самый нижний файл */
lCurrentFile.parentElement.lastElementChild.className=CloudCommander.CURRENT_FILE;
}
/* если нажали Enter - открываем папку*/
else if(event.keyCode===13){
lCurrentFile = Util.getByClass(CloudCommander.CURRENT_FILE);
/* если ненайдены выделенные файлы - выходим*/
if(!lCurrentFile.length)return;
lCurrentFile=lCurrentFile[0];
/* из него достаём спан с именем файла*/
lName=lCurrentFile.getElementsByClassName('name');
/* если нету (что вряд ли) - выходим*/
if(!lName)return false;
/* достаём все ссылки*/
var lATag=lName[0].getElementsByTagName('a');
/* если нету - выходим */
if(!lATag)return false;
/* вызываем 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 = Util
.getByClass(CloudFunc.REFRESHICON);
if(lRefreshIcon)lRefreshIcon = lRefreshIcon[0];
if(lRefreshIcon){
/* находим файл который сейчас выделен */
lCurrentFile = Util
.getByClass(CloudCommander.CURRENT_FILE);
if(lCurrentFile.length > 0)
lCurrentFile=lCurrentFile[0];
/* получаем название файла*/
var lSelectedName = lCurrentFile
.getElementsByTagName('a')[0].textContent;
/* если нашли элемент нажимаем него
* а если не можем - нажимаем на
* ссылку, на которую повешен eventHandler
* onclick
*/
if(lRefreshIcon.click)lRefreshIcon.parentElement.click();
else lRefreshIcon.parentElement.onclick();
/* перебираем файлы левой панели
* в поисках подсвеченого файла
*/
var lLeft = Util.getById('left');
if(lLeft)
CloudCommander._currentToParent(lSelectedName);
}
}
/* если нажали <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 = Util.getById('clear-cache');
if(lClearCache && lClearCache.onclick)lClearCache.onclick();
}
/* если нажали <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');
/* обработчик нажатий клавиш снят*/
CloudCommander.keyBinded=false;
}
event.preventDefault();//запрет на дальнейшее действие
}
/* если нажали <alt>+s
* устанавливаем все обработчики
* нажатий клавиш
*/
else if(event.keyCode===83 &&
event.altKey){
/*
document.addEventListener('keydown', key_event,false);
*/
/* обрабатываем нажатия на клавиши*/
CloudCommander.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;
/* клавиши назначены*/
CloudCommander.keyBinded=true;
});

76
lib/client/terminal.js Normal file
View file

@ -0,0 +1,76 @@
var CloudCommander, jqconsole;
/* object contains terminal jqconsole
*/
CloudCommander.Terminal = {};
CloudCommander.Terminal.jqconsole = {
load: function(pParent){
CloudCommander.cssLoad({
src : 'lib/client/terminal/ansi.css'
});
CloudCommander.jsload({
src : 'lib/client/terminal/jqconsole-2.7.min.js',
func : function(){
pParent.init();
}
});
},
init: (function(){
var pConsole = document.getById('terminal');
if(!pConsole){
CloudCommander.anyload({
name : 'div',
id :'terminal'
});
}
}),
show: function(){
$(function () {
var jqconsole = $('#terminal').jqconsole('Hi\n', '>>>');
var startPrompt = function () {
// Start the prompt with history enabled.
jqconsole.Prompt(true, function (input) {
// Output input with the class jqconsole-output.
jqconsole.Write(input + '\n', 'jqconsole-output');
// Restart the prompt.
startPrompt();
});
};
startPrompt();
});
},
getById : function(pId){return document.getElementById(pId);},
getByClass : function(pClass){
return document.getElementsByClassName(pClass);
}
};
CloudCommander.Terminal.Keys = (function(){
"use strict";
/* loading js and css of CodeMirror */
CloudCommander.Editor.Terminal.load(this.jqconsole);
var key_event=function(event){
/* если клавиши можно обрабатывать */
if(CloudCommander.keyBinded){
/* if f4 pressed */
if(event.keyCode===114 &&
event.altKey){
CloudCommander.Terminal.jqconsole.show();
}
}
};
/* добавляем обработчик клавишь */
if (document.addEventListener)
document.addEventListener('keydown', key_event,false);
else
document.onkeypress=key_event;
});

View file

@ -0,0 +1,107 @@
#jq-console
A simple jQuery terminal plugin written in CoffeeScript.
This project was spawned because of our need for a simple web terminal plugin
for the <a href="http://github.com/amasad/jsrepl">jsREPL</a> project. It
tries to simulate a low level terminal by providing (almost) raw input/output
streams as well as input and output states.
##Tested Browsers
The plugin has been tested on the following browsers:
* IE 8
* Chrome 10
* Firefox 3.6
* Safari 4
* Opera 10
##Getting Started
###Instantiating
var jqconsole = $(div).jqconsole(welcomeString);
* `div` is the div element or selector.
* `welcomeString` is the string to be shown when the terminal is first rendered.
###Configuration
There isn't much initial configuration needed, because the user must supply
options and callbacks with each state change. The only config method is used to
create custom shortcuts:
* `jqconsole.RegisterShortcut`: Registers a callback for a keyboard shortcut.
It takes two arguments:
* `int keyCode`: The code of the key pressing which (when Ctrl is held) will
trigger this shortcut.
* `function callback`: A function called when the shortcut is pressed;
"this" will point to the JQConsole object.
Example:
// Ctrl+R: resets the console.
jqconsole.RegisterShortCut(82, function() {
this.Reset();
});
##Usage
Unlike most terminal plugins, jq-console gives you complete low-level control
over the execution; you have to call the appropriate methods to start input
or output:
* `jqconsole.Input`: Asks user for input. It takes three arguments:
* `bool history_enabled`: Whether this input should use history. If true,
the user can select the input from history, and their input will also be
added as a new history item.
* `function result_callback`: A function called with the user's input when
the user presses Enter and the input operation is complete.
* `function multiline_callback`: If specified, this function is called when
the user presses Enter to check whether the input should continue to the
next line. If this function returns a falsy value, the input operation
is completed. Otherwise, input continues and the cursor moves to the next
line.
Example:
jqconsole.Input(true, function(input) {
alert(input);
}, function (input) {
return /\\$/.test('asdasd \\');
});
* `jqconsole.Write`: Writes the given text to the console in a `<span>`, with an
optional class. This is used for output and writing prompt labels. It takes
two arguments:
* `string text`: The text to write.
* `string cls`: The class to give the span containing the text. Optional.
Examples:
jqconsole.Write('>>>', 'prompt')
jqconsole.Write(output, 'output')
jqconsole.Write(err.message, 'error')
* `jqconsole.SetPromptText` Sets the text currently in the input prompt. Takes
only one parameter:
* `string text`: The text to put in the prompt.
Examples:
jqconsole.SetPromptText('ls')
jqconsole.SetPromptText('print [i ** 2 for i in range(10)]')
##Contributors
[Max Shawabkeh](http://max99x.com/)
[Amjad Masad](http://twitter.com/amjad_masad)

View file

@ -0,0 +1,678 @@
#jq-console
A jQuery terminal plugin written in CoffeeScript.
This project was spawned because of our need for a simple web terminal plugin
for the <a href="http://repl.it">repl.it</a> project. It tries to simulate a low level terminal by providing (almost)
raw input/output streams as well as input and output states.
Version 2.0 adds baked-in support for rich multi-line prompting and operation
queueing.
NOTE: This info is for jq-console v2.0. For jq-console v1.0 see README-v1.md.
##Tested Browsers
The plugin has been tested on the following browsers:
* IE 9-10
* Chrome 10-14
* Firefox 3.6-6
* Opera 11
##Getting Started
###Echo example
```css
/* The console container element */
#console {
position: absolute;
width: 400px;
height: 500px;
background-color:black;
}
/* The inner console element. */
.jqconsole {
padding: 10px;
}
/* The cursor. */
.jqconsole-cursor {
background-color: gray;
}
/* The cursor color when the console looses focus. */
.jqconsole-blurred .jqconsole-cursor {
background-color: #666;
}
/* The current prompt text color */
.jqconsole-prompt {
color: #0d0;
}
/* The command history */
.jqconsole-old-prompt {
color: #0b0;
font-weight: normal;
}
/* The text color when in input mode. */
.jqconsole-input {
color: #dd0;
}
/* Previously entered input. */
.jqconsole-old-input {
color: #bb0;
font-weight: normal;
}
/* The text color of the output. */
.jqconsole-output {
color: white;
}
```
```html
<div id="console"></div>
<script src="jquery.js" type="text/javascript" charset="utf-8"></script>
<script src="jqconsole.js" type="text/javascript" charset="utf-8"></script>
<script>
$(function () {
var jqconsole = $('#console').jqconsole('Hi\n', '>>>');
var startPrompt = function () {
// Start the prompt with history enabled.
jqconsole.Prompt(true, function (input) {
// Output input with the class jqconsole-output.
jqconsole.Write(input + '\n', 'jqconsole-output');
// Restart the prompt.
startPrompt();
});
};
startPrompt();
});
</script>
```
<iframe src="demo/echo.html" style="width:400px;height:500px">
</iframe>
###Instantiating
```javascript
$(div).jqconsole(welcomeString, promptLabel, continueLabel);
```
* `div` is the div element or selector. Note that this element must be
explicity sized and positioned `absolute` or `relative`.
* `welcomeString` is the string to be shown when the terminal is first rendered.
* `promptLabel` is the label to be shown before the input when using Prompt().
* `continueLabel` is the label to be shown before the continued lines of the
input when using Prompt().
##Configuration
There isn't much initial configuration needed, because the user must supply
options and callbacks with each state change. There are a few config methods
provided to create custom shortcuts and change indentation width:
###jqconsole.RegisterShortcut
Registers a callback for a keyboard shortcut.
Takes two arguments:
* __(int|string)__ *keyCode*: The code of the key pressing which (when Ctrl is
held) will trigger this shortcut. If a string is provided, the ASCII code
of the first character is taken.
* __function__ *callback*: A function called when the shortcut is pressed;
"this" will point to the JQConsole object.
Example:
// Ctrl+R: resets the console.
jqconsole.RegisterShortcut('R', function() {
this.Reset();
});
###jqconsole.SetIndentWidth
Sets the number of spaces inserted when indenting and removed when unindenting.
Takes one argument:
* __int__ *width*: The code of the key pressing which (when Ctrl is held) will
trigger this shortcut.
Example:
// Sets the indent width to 4 spaces.
jqconsole.SetIndentWidth(4);
###jqconsole.RegisterMatching
Registers an opening and closing characters to match and wraps each of the
opening and closing characters with a span with the specified class.
Takes one parameters:
* __char__ *open*: The opening character of a "block".
* __char__ *close*: The closing character of a "block".
* __string__ *class*: The css class that is applied to the matched characters.
Example:
jqconsole.RegisterMatching('{', '}', 'brackets');
##Usage
Unlike most terminal plugins, jq-console gives you complete low-level control
over the execution; you have to call the appropriate methods to start input
or output:
###jqconsole.Input:
Asks user for input. If another input or prompt operation is currently underway,
the new input operation is enqueued and will be called when the current
operation and all previously enqueued operations finish. Takes one argument:
* __function__ *input_callback*: A function called with the user's input when
the user presses Enter and the input operation is complete.
Example:
// Echo the input.
jqconsole.Input(function(input) {
jqconsole.Write(input);
});
###jqconsole.Prompt
Asks user for input. If another input or prompt operation is currently underway
the new prompt operation is enqueued and will be called when the current
peration and all previously enqueued operations finish. Takes three arguments:
* __bool__ *history_enabled*: Whether this input should use history. If true,
the user can select the input from history, and their input will also be
added as a new history item.
* __function__ *result_callback*: A function called with the user's input when
the user presses Enter and the prompt operation is complete.
* __function__ *multiline_callback*: If specified, this function is called when
the user presses Enter to check whether the input should continue to the
next line. The function must return one of the following values:
* `false`: the input operation is completed.
* `0`: the input continues to the next line with the current indent.
* `N` (int): the input continues to the next line, and the current
indent is adjusted by `N`, e.g. `-2` to unindent two levels.
* __bool__ *async_multiline*: Whether the multiline callback function should
be treated as an asynchronous operation and be passed a continuation
function that should be called with one of the return values mentioned
above: `false`/`0`/`N`.
Example:
jqconsole.Prompt(true, function(input) {
// Alert the user with the command.
alert(input);
}, function (input) {
// Continue if the last character is a backslash.
return /\\$/.test(input);
});
###jqconsole.AbortPrompt
Aborts the current prompt operation and returns to output mode or the next
queued input/prompt operation. Takes no arguments.
Example:
jqconsole.Prompt(true, function(input) {
alert(input);
});
// Give the user 2 seconds to enter the command.
setTimeout(function() {
jqconsole.AbortPrompt();
}, 2000);
###jqconsole.Write
Writes the given text to the console in a `<span>`, with an
optional class. If a prompt is currently being shown, the text is inserted
before it. Takes two arguments:
* __string__ *text*: The text to write.
* __string__ *cls*: The class to give the span containing the text. Optional.
* __bool__ *escape*: Whether the text to write should be html escaped.
Optional, defaults to true.
Examples:
jqconsole.Write(output, 'my-output-class')
jqconsole.Write(err.message, 'my-error-class')
###jqconsole.SetPromptText
Sets the text currently in the input prompt. Takes one parameter:
* __string__ *text*: The text to put in the prompt.
Examples:
jqconsole.SetPromptText('ls')
jqconsole.SetPromptText('print [i ** 2 for i in range(10)]')
###jqconsole.ClearPromptText
Clears all the text currently in the input prompt. Takes one parameter:
* __bool__ *clear_label*: If specified and true, also clears the main prompt
label (e.g. ">>>").
Example:
jqconsole.ClearPromptText()
###jqconsole.GetPromptText
Returns the contents of the prompt. Takes one parameter:
* __bool__ *full*: If specified and true, also includes the prompt labels
(e.g. ">>>").
Examples:
var currentCommand = jqconsole.GetPromptText()
var logEntry = jqconsole.GetPromptText(true)
###jqconsole.Reset
Resets the console to its initial state, cancelling all current and pending
operations. Takes no parameters.
Example:
jqconsole.Reset()
###jqconsole.GetColumn
Returns the 0-based number of the column on which the cursor currently is.
Takes no parameters.
Example:
// Show the current line and column in a status area.
$('#status').text(jqconsole.GetLine() + ', ' + jqconsole.GetColumn())
###jqconsole.GetLine
Returns the 0-based number of the line on which the cursor currently is.
Takes no parameters.
Example:
// Show the current line and column in a status area.
$('#status').text(jqconsole.GetLine() + ', ' + jqconsole.GetColumn())
###jqconsole.Focus
Forces the focus onto the console so events can be captured.
Takes no parameters.
Example:
// Redirect focus to the console whenever the user clicks anywhere.
$(window).click(function() {
jqconsole.Focus();
})
###jqconsole.GetIndentWidth
Returns the number of spaces inserted when indenting. Takes no parameters.
Example:
jqconsole.SetIndentWidth(4);
console.assert(jqconsole.GetIndentWidth() == 4);
###jqconsole.UnRegisterMatching
Deletes a certain matching settings set by `jqconsole.RegisterMatching`.
Takes two paramaters:
* __char__ *open*: The opening character of a "block".
* __char__ *close*: The closing character of a "block".
Example:
jqconsole.UnRegisterMatching('{', '}');
###jqconsole.Dump
Returns the text content of the console.
###jqconsole.GetState
Returns the current state of the console. Could be one of the following:
* Input: `"input"`
* Output: `"output"`
* Prompt: `"prompt"`
Example:
jqconsole.GetState(); //output
###jqconsole.MoveToStart
Moves the cursor to the start of the current line.
Takes one parameter:
* __bool__ *all_lines*: If true moves the cursor to the beginning of the first
line in the current prompt. Defaults to false.
Example:
// Move to line start Ctrl+A.
jqconsole.RegisterShortcut('A', function() {
jqconsole.MoveToStart();
handler();
});
###jqconsole.MoveToEnd
Moves the cursor to the end of the current line.
Takes one parameter:
* __bool__ *all_lines*: If true moves the cursor to the end of the first
line in the current prompt. Defaults to false.
Example:
// Move to line end Ctrl+E.
jqconsole.RegisterShortcut('E', function() {
jqconsole.MoveToEnd();
handler();
});
###jqconsole.Disable
Disables input and focus on the console.
###jqconsole.Enable
Enables input and focus on the console.
###jqconsole.IsDisabled
Returns true if the console is disabled.
###jqconsole.ResetHistory
Resets the console history.
###jqconsole.ResetMatchings
Resets the character matching configuration.
###jqconsole.ResetShortcuts
Resets the shortcut configuration.
##Default Key Config
The console responds to the followind keys and key combinations by default:
* `Delete`: Delete the following character.
* `Ctrl+Delete`: Delete the following word.
* `Backspace`: Delete the preceding character.
* `Ctrl+Backspace`: Delete the preceding word.
* `Ctrl+Left`: Move one word to the left.
* `Ctrl+Right`: Move one word to the right.
* `Home`: Move to the beginning of the current line.
* `Ctrl+Home`: Move to the beginnig of the first line.
* `End`: Move to the end of the current line.
* `Ctrl+End`: Move to the end of the last line.
* `Shift+Up`, `Ctrl+Up`: Move cursor to the line above the current one.
* `Shift+Down`, `Ctrl+Down`: Move cursor to the line below the current one.
* `Tab`: Indent.
* `Shift+Tab`: Unindent.
* `Up`: Previous history item.
* `Down`: Next history item.
* `Enter`: Finish input/prompt operation. See Input() and Prompt() for details.
* `Shift+Enter`: New line.
* `Page Up`: Scroll console one page up.
* `Page Down`: Scroll console one page down.
##ANSI escape code SGR support
jq-console implements a large subset of the ANSI escape code graphics.
Using the `.Write` method you could add style to the console using
the following syntax:
`ASCII 27 (decimal) or 0x1b (hex)` `[` `SGR code` `m`
Example:
jqconsole.Write('\033[31mRed Text');
Note that the third parameter `escape` must be true which defaults to it.
You'll need to include the `ansi.css` file for default effects or create your
own using the css classes from the table below.
###SGR
[Reference](http://en.wikipedia.org/wiki/ANSI_escape_code#graphics).
<table>
<tr>
<th>Code</th>
<th>Effect</th>
<th>Class</th>
</tr>
<tr>
<td>0</td>
<td>Reset / Normal</td>
<td></td>
</tr>
<tr>
<td>1</td>
<td>Bold</td>
<td>`jqconsole-ansi-bold`</td>
</tr>
<tr>
<td>2</td>
<td>Faint</td>
<td>`jqconsole-ansi-lighter`</td>
</tr>
<tr>
<td>3</td>
<td>Italic</td>
<td>`jqconsole-ansi-italic`</td>
</tr>
<tr>
<td>4</td>
<td>Line below text</td>
<td>`jqconsole-ansi-underline`</td>
</tr>
<tr>
<td>5</td>
<td>Blink: 1s delay</td>
<td>`jqconsole-ansi-blink`</td>
</tr>
<tr>
<td>6</td>
<td>Blink: 0.5s delay</td>
<td>`jqconsole-ansi-blink-rapid`</td>
</tr>
<tr>
<td>8</td>
<td>Hide text</td>
<td>`jqconsole-ansi-hidden`</td>
</tr>
<tr>
<td>9</td>
<td>Line through text</td>
<td>`jqconsole-ansi-line-through`</td>
</tr>
<tr>
<td>10</td>
<td>Remove all fonts</td>
<td></td>
</tr>
<tr>
<td>11-19</td>
<td>Add custom font</td>
<td>`jqconsole-ansi-fonts-{N}` where N is code - 10</td>
</tr>
<tr>
<td>20</td>
<td>Add Fraktur font (not implemented in ansi.css)</td>
<td>`jqconsole-ansi-fraktur`</td>
</tr>
<tr>
<td>21</td>
<td>Remove Bold and Faint effects</td>
<td></td>
</tr>
<tr>
<td>22</td>
<td>Same as 21</td>
<td></td>
</tr>
<tr>
<td>23</td>
<td>Remove italic and fraktur effects</td>
<td></td>
</tr>
<tr>
<td>24</td>
<td>Remove underline effect</td>
<td></td>
</tr>
<tr>
<td>25</td>
<td>Remove blinking effect(s).</td>
<td></td>
</tr>
<tr>
<td>28</td>
<td>Reveal text</td>
<td></td>
</tr>
<tr>
<td>29</td>
<td>Remove line-through effect</td>
<td></td>
</tr>
<tr>
<td>30-37</td>
<td>Set foreground color to color from the color table below</td>
<td>jqconsole-ansi-color-{COLOR} where {COLOR} is the color name</td>
</tr>
<tr>
<td>39</td>
<td>Restore default foreground color</td>
<td></td>
</tr>
<tr>
<td>40-47</td>
<td>Set background color to color from the color table below</td>
<td>`jqconsole-ansi-background-color-{COLOR}` where {COLOR} is the color name</td>
</tr>
<tr>
<td>49</td>
<td>Restore default background color</td>
<td></td>
</tr>
<tr>
<td>51</td>
<td>Adds a frame around the text</td>
<td>`jqconsole-ansi-framed`</td>
</tr>
<tr>
<td>53</td>
<td>Line above text</td>
<td>jqconsole-ansi-overline</td>
</tr>
<tr>
<td>54</td>
<td>Remove frame effect</td>
<td></td>
</tr>
<tr>
<td>55</td>
<td>Remove over-line effect</td>
<td></td>
</tr>
</table>
###Colors
[Reference](http://en.wikipedia.org/wiki/ANSI_escape_code#Colors).
<table>
<tr>
<th>Code offset</th>
<th>Color</th>
</tr>
<tr>
<td>0</td>
<td>Black</td>
</tr>
<tr>
<td>1</td>
<td>Red</td>
</tr>
<tr>
<td>2</td>
<td>Green</td>
</tr>
<tr>
<td>3</td>
<td>Yellow</td>
</tr>
<tr>
<td>4</td>
<td>Blue</td>
</tr>
<tr>
<td>5</td>
<td>Magenta</td>
</tr>
<tr>
<td>6</td>
<td>Cyan</td>
</tr>
<tr>
<td>7</td>
<td>White</td>
</tr>
</table>
##CSS Classes
Several CSS classes are provided to help stylize the console:
* `jqconsole`: The main console container.
* `jqconsole, jqconsole-blurred`: The main console container, when not in focus.
* `jqconsole-cursor`: The cursor.
* `jqconsole-header`: The welcome message at the top of the console.
* `jqconsole-input`: The prompt area during input. May have multiple lines.
* `jqconsole-old-input`: Previously-entered inputs.
* `jqconsole-prompt`: The prompt area during prompting. May have multiple lines.
* `jqconsole-old-prompt`: Previously-entered prompts.
* `jqconsole-composition`: The div encapsulating the composition of multi-byte
characters.
Of course, custom classes may be specified when using `jqconsole.Write()` for
further customization.
##Contributors
[Max Shawabkeh](http://max99x.com/)
[Amjad Masad](http://twitter.com/amjad_masad)

View file

@ -0,0 +1,172 @@
.jqconsole-ansi-bold {
font-weight: bold!important;
}
.jqconsole-ansi-lighter {
font-weight: lighter!important;
}
.jqconsole-ansi-italic {
font-style: italic!important;
}
.jqconsole-ansi-underline {
text-decoration: underline!important;
}
@-webkit-keyframes blinker {
from { opacity: 1.0; }
to { opacity: 0.0; }
}
@-moz-keyframes blinker {
from { opacity: 1.0; }
to { opacity: 0.0; }
}
@-ms-keyframes blinker {
from { opacity: 1.0; }
to { opacity: 0.0; }
}
@-o-keyframes blinker {
from { opacity: 1.0; }
to { opacity: 0.0; }
}
.jqconsole-ansi-blink {
-webkit-animation-name: blinker;
-moz-animation-name: blinker;
-ms-animation-name: blinker;
-o-animation-name: blinker;
-webkit-animation-iteration-count: infinite;
-moz-animation-iteration-count: infinite;
-ms-animation-iteration-count: infinite;
-o-animation-iteration-count: infinite;
-webkit-animation-timing-function: cubic-bezier(1.0,0,0,1.0);
-ms-animation-timing-function: cubic-bezier(1.0,0,0,1.0);
-o-animation-timing-function: cubic-bezier(1.0,0,0,1.0);
-moz-animation-timing-function: cubic-bezier(1.0,0,0,1.0);
-webkit-animation-duration: 1s;
-moz-animation-duration: 1s;
-o-animation-duration: 1s;
-ms-animation-duration: 1s;
}
.jqconsole-ansi-blink-rapid {
-webkit-animation-name: blinker;
-moz-animation-name: blinker;
-ms-animation-name: blinker;
-o-animation-name: blinker;
-webkit-animation-iteration-count: infinite;
-moz-animation-iteration-count: infinite;
-ms-animation-iteration-count: infinite;
-o-animation-iteration-count: infinite;
-webkit-animation-timing-function: cubic-bezier(1.0,0,0,1.0);
-ms-animation-timing-function: cubic-bezier(1.0,0,0,1.0);
-o-animation-timing-function: cubic-bezier(1.0,0,0,1.0);
-moz-animation-timing-function: cubic-bezier(1.0,0,0,1.0);
-webkit-animation-duration: 0.5s;
-moz-animation-duration: 0.5s;
-o-animation-duration: 0.5s;
-ms-animation-duration: 0.5s;
}
.jqconsole-ansi-hidden {
visibility:hidden!important;
}
.jqconsole-ansi-line-through {
text-decoration: line-through;
}
.jqconsole-ansi-fonts-1 {
}
.jqconsole-ansi-fonts-2 {
}
.jqconsole-ansi-fonts-3 {
}
.jqconsole-ansi-fonts-4 {
}
.jqconsole-ansi-fonts-5 {
}
.jqconsole-ansi-fonts-6 {
}
.jqconsole-ansi-fonts-7 {
}
.jqconsole-ansi-fonts-8 {
}
.jqconsole-ansi-fonts-9 {
}
.jqconsole-ansi-fraktur {
}
.jqconsole-ansi-color-black {
color: black!important;
}
.jqconsole-ansi-color-red {
color: red!important;
}
.jqconsole-ansi-color-green {
color: green!important;
}
.jqconsole-ansi-color-yellow {
color: yellow!important;
}
.jqconsole-ansi-color-blue {
color: blue!important;
}
.jqconsole-ansi-color-magenta {
color: magenta!important;
}
.jqconsole-ansi-color-cyan {
color: cyan!important;
}
.jqconsole-ansi-color-white {
color: white!important;
}
.jqconsole-ansi-background-color-black {
background-color: black!important;
}
.jqconsole-ansi-background-color-red {
background-color: red!important;
}
.jqconsole-ansi-background-color-green {
background-color: green!important;
}
.jqconsole-ansi-background-color-yellow {
background-color: yellow!important;
}
.jqconsole-ansi-background-color-blue {
background-color: blue!important;
}
.jqconsole-ansi-background-color-magenta {
background-color: magenta!important;
}
.jqconsole-ansi-background-color-cyan {
background-color: cyan!important;
}
.jqconsole-ansi-background-color-white {
background-color: white!important;
}
.jqconsole-ansi-framed {
border: 1px solid!important;
}
.jqconsole-ansi-overline {
text-decoration: overline!important;
}

File diff suppressed because it is too large Load diff

View file

@ -1,149 +1,134 @@
var CloudCommander, CloudFunc, $;
/* object contains viewer FancyBox
* https://github.com/fancyapps/fancyBox
*/
CloudCommander.Viewer = {
dir : CloudCommander.LIBDIRCLIENT + 'viewer/',
getByClass : function(pClass){
return document.getElementsByClassName(pClass);
}
};
CloudCommander.Viewer.FancyBox = {
dir : CloudCommander.Viewer.dir + 'fancybox/',
/* function return configureation
* for FancyBox open and
* onclick (it shoud be
* different objects)
*/
getConfig: (function(){
return{
beforeShow : (function(){
CloudCommander.keyBinded = false;
}),
beforeClose: (function(){
CloudCommander.keyBinded = true;
}),
openEffect : 'none',
closeEffect : 'none',
helpers : {
overlay : {
opacity: 0.1,
css : {
'background-color' : '#fff'
}
}
},
padding : 0
};
}),
/* function loads css and js of FancyBox
* @pParent - this
* @pCallBack - executes, when everything loaded
*/
load: (function(pParent, pCallBack){
return function(){
var ljsLoad_f = function(){
var lSrc = 'http://fancyapps.com/fancybox/source/jquery.fancybox.pack.js';
CloudCommander.jsload(lSrc,{
onload: pCallBack,
onerror: (function() {
CloudCommander.jsload(pParent.dir +
'jquery.fancybox.pack.js', {onload: pCallBack});
})
});
};
var lSrc = 'http://fancyapps.com/fancybox/source/jquery.fancybox.css';
CloudCommander.cssLoad({
src : lSrc,
func : {
onload: ljsLoad_f,
onerror: (function() {
CloudCommander.cssLoad({
src : pParent.dir +'jquery.fancybox.css',
func : ljsLoad_f
});
})
}
});
}();
}),
set: function(){
if(this.getByClass('fancybox').length)
return;
try{
/* get current panel (left or right) */
var lPanel = this.getByClass('current-file');
lPanel.length &&
(lPanel = lPanel[0].parentElement);
/* get all file links */
var lA = lPanel.getElementsByTagName('a');
var lName;
/* first two is not files nor folders*/
for (var i=2; i < lA.length; i++) {
lName = lA[i].title || lA[i].textContent;
CloudFunc.checkExtension(lName,['png','jpg']) &&
(lA[i].className = 'fancybox') &&
(lA[i].rel = 'gallery');
}
$('.fancybox').fancybox(this.getConfig());
}catch(pError){
console.log(pError);
}
},
getById : function(pId){return document.getElementById(pId);},
getByClass : function(pClass){
return document.getElementsByClassName(pClass);
}
};
CloudCommander.Viewer.Keys = (function(){
"use strict";
var lCallBack_f = (function(pParent){
var key_event = function(){
return function(event){
/* если клавиши можно обрабатывать */
if(CloudCommander.keyBinded){
/* if f3 pressed */
if(event.keyCode===114){
CloudCommander.Viewer.FancyBox.set();
var lCurrent = pParent.getByClass('current-file');
lCurrent.length &&
(lCurrent = lCurrent[0]);
var lA = lCurrent.getElementsByClassName('fancybox');
var lConfig = pParent.FancyBox.getConfig();
lA.length &&
$.fancybox.open({ href : lA[0].href },
lConfig);
event.preventDefault();
}
}
};
};
/* добавляем обработчик клавишь */
if (document.addEventListener)
document.addEventListener('keydown', key_event(pParent),false);
else
document.onkeypress=key_event;
});
CloudCommander.Viewer.FancyBox.load(this.FancyBox, lCallBack_f(this));
var CloudCommander, CloudFunc, $;
/* object contains viewer FancyBox
* https://github.com/fancyapps/fancyBox
*/
CloudCommander.Viewer = {
dir : './lib/client/viewer/'
};
CloudCommander.Viewer.FancyBox = new CloudCommander.Util();
CloudCommander.Viewer.FancyBox.dir = CloudCommander.Viewer.dir +
'fancybox/';
/* function return configureation
* for FancyBox open and
* onclick (it shoud be
* different objects)
*/
CloudCommander.Viewer.FancyBox.getConfig = (function(){
return{
beforeShow : (function(){
CloudCommander.keyBinded = false;
}),
beforeClose: (function(){
CloudCommander.keyBinded = true;
}),
openEffect : 'none',
closeEffect : 'none',
helpers : {
overlay : {
opacity: 0.1,
css : {
'background-color' : '#fff'
}
}
},
padding : 0
};
});
/* function loads css and js of FancyBox
* @pParent - this
* @pCallBack - executes, when everything loaded
*/
CloudCommander.Viewer.FancyBox.load = (function(pParent, pCallBack){
return function(){
var ljsLoad_f = function(){
var lSrc = pParent.dir + 'jquery.fancybox.pack.js';
pParent.jsload(lSrc,{
onload: pCallBack
});
};
var lSrc = pParent.dir +'jquery.fancybox.pack.css';
pParent.cssLoad({
src : lSrc,
func : {
onload: ljsLoad_f
}
});
}();
});
CloudCommander.Viewer.FancyBox.set = (function(){
if(this.getByClass('fancybox').length)
return;
try{
/* get current panel (left or right) */
var lPanel = this.getPanel();
/* get all file links */
var lA = lPanel.getElementsByTagName('a');
var lName;
/* first two is not files nor folders*/
for (var i=2; i < lA.length; i++) {
lName = lA[i].title || lA[i].textContent;
CloudFunc.checkExtension(lName,
['png','jpg', 'gif','ico']) &&
(lA[i].className = 'fancybox') &&
(lA[i].rel = 'gallery');
}
$('.fancybox').fancybox(this.getConfig());
}catch(pError){
console.log(pError);
}
});
CloudCommander.Viewer.FancyBox.show = (function(pParent){
CloudCommander.Viewer.FancyBox.set();
var lCurrent = this.getCurrentFile();
var lA = lCurrent.getElementsByClassName('fancybox');
var lConfig = this.getConfig();
lA.length &&
$.fancybox.open({ href : lA[0].href },
lConfig);
});
CloudCommander.Viewer.Keys = (function(){
"use strict";
var lCallBack_f = (function(){
var key_event = (function(){
return function(event){
/* если клавиши можно обрабатывать */
if(CloudCommander.keyBinded)
/* if f3 pressed */
if(event.keyCode===114){
CloudCommander.Viewer.FancyBox.show();
event.preventDefault();
}
};
});
/* добавляем обработчик клавишь */
if (document.addEventListener)
document.addEventListener('keydown', key_event(),false);
else
document.onkeypress=key_event;
/* showing images preview*/
CloudCommander.Viewer.FancyBox.show();
});
CloudCommander.Viewer.FancyBox.load(this.FancyBox, lCallBack_f);
});

View file

@ -0,0 +1 @@
/*! fancyBox v2.0.6 fancyapps.com | fancyapps.com/fancybox/#license */.fancybox-wrap,.fancybox-skin,.fancybox-outer,.fancybox-inner,.fancybox-image,.fancybox-wrap iframe,.fancybox-wrap object,.fancybox-nav,.fancybox-nav span,.fancybox-tmp{padding:0;margin:0;border:0;outline:0;vertical-align:top}.fancybox-wrap{position:absolute;top:0;left:0;z-index:8020}.fancybox-skin{position:relative;background:#f9f9f9;color:#444;text-shadow:none;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.fancybox-opened{z-index:8030}.fancybox-opened .fancybox-skin{-webkit-box-shadow:0 10px 25px rgba(0,0,0,.5);-moz-box-shadow:0 10px 25px rgba(0,0,0,.5);box-shadow:0 10px 25px rgba(0,0,0,.5)}.fancybox-outer,.fancybox-inner{position:relative}.fancybox-inner{overflow:hidden}.fancybox-type-iframe .fancybox-inner{-webkit-overflow-scrolling:touch}.fancybox-error{color:#444;font:14px/20px "Helvetica Neue",Helvetica,Arial,sans-serif;margin:0;padding:15px;white-space:nowrap}.fancybox-image,.fancybox-iframe{display:block;width:100%;height:100%}.fancybox-image{max-width:100%;max-height:100%}#fancybox-loading,.fancybox-close,.fancybox-prev span,.fancybox-next span{background-image:url('fancybox_sprite.png')}#fancybox-loading{position:fixed;top:50%;left:50%;margin-top:-22px;margin-left:-22px;background-position:0 -108px;opacity:.8;cursor:pointer;z-index:8060}#fancybox-loading div{width:44px;height:44px;background:url('fancybox_loading.gif') center center no-repeat}.fancybox-close{position:absolute;top:-18px;right:-18px;width:36px;height:36px;cursor:pointer;z-index:8040}.fancybox-nav{position:absolute;top:0;width:40%;height:100%;cursor:pointer;text-decoration:none;background:transparent url('blank.gif');-webkit-tap-highlight-color:rgba(0,0,0,0);z-index:8040}.fancybox-prev{left:0}.fancybox-next{right:0}.fancybox-nav span{position:absolute;top:50%;width:36px;height:34px;margin-top:-18px;cursor:pointer;z-index:8040;visibility:hidden}.fancybox-prev span{left:10px;background-position:0 -36px}.fancybox-next span{right:10px;background-position:0 -72px}.fancybox-nav:hover span{visibility:visible}.fancybox-tmp{position:absolute;top:-9999px;left:-9999px;visibility:hidden}#fancybox-overlay{position:absolute;top:0;left:0;overflow:hidden;display:none;z-index:8010;background:#000}#fancybox-overlay.overlay-fixed{position:fixed;bottom:0;right:0}.fancybox-title{visibility:hidden;font:normal 13px/20px "Helvetica Neue",Helvetica,Arial,sans-serif;position:relative;text-shadow:none;z-index:8050}.fancybox-opened .fancybox-title{visibility:visible}.fancybox-title-float-wrap{position:absolute;bottom:0;right:50%;margin-bottom:-35px;z-index:8050;text-align:center}.fancybox-title-float-wrap .child{display:inline-block;margin-right:-100%;padding:2px 20px;background:transparent;background:rgba(0,0,0,.8);-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px;text-shadow:0 1px 2px #222;color:#FFF;font-weight:700;line-height:24px;white-space:nowrap}.fancybox-title-outside-wrap{position:relative;margin-top:10px;color:#fff}.fancybox-title-inside-wrap{padding-top:10px}.fancybox-title-over-wrap{position:absolute;bottom:0;left:0;color:#fff;padding:10px;background:#000;background:rgba(0,0,0,.8)}

View file

@ -100,7 +100,7 @@ exports.Minify={
}catch(pError){
this._allowed={js:false,css:false,html:false};
return console.log('Could not minify ' +
'withou minify module\n' +
'without minify module\n' +
'npm i minify');
}

3
lib/server/win.js Normal file
View file

@ -0,0 +1,3 @@
/* Library contain windows specific functions
* like getting information about volumes
*/

View file

@ -0,0 +1 @@
diskpart /s getvolumes.txt

View file

@ -0,0 +1 @@
list volumes

1463
server.js

File diff suppressed because it is too large Load diff