cloudcmd/lib/client/dom.js
2012-11-27 05:05:04 -05:00

1034 lines
No EOL
30 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

var CloudCommander, Util, DOM, CloudFunc;
(function(){
"use strict";
DOM = {};
/* PRIVATE */
function getCurrentFile(){
return CloudCommander.CURRENT_FILE;
}
/**
* private function thet unset currentfile
*/
function UnSetCurrentFile(pCurrentFile){
var lRet_b = DOM.isCurrentFile(pCurrentFile);
if(!pCurrentFile)
DOM.addCloudStatus({
code : -1,
msg : 'Error pCurrentFile in' +
'unSetCurrentFile' +
'could not be none'
});
if(lRet_b)
DOM.removeClass(pCurrentFile, getCurrentFile());
return lRet_b;
}
/* private members */
var XMLHTTP,
LoadingImage,
ErrorImage,
/* Обьект, который содержит
* функции для отображения
* картинок
*/
Images_o = {
/* Функция создаёт картинку загрузки*/
loading : function(){
var lE = DOM.getById('loading-image');
if (!lE)
lE = DOM.anyload({
name : 'span',
className : 'icon loading',
id : 'loading-image',
not_append : true
});
LoadingImage = lE;
return lE;
},
/* Функция создаёт картинку ошибки загрузки*/
error : function(){
var lE = DOM.getById('error-image');
if (!lE)
lE = DOM.anyload({
name : 'span',
className : 'icon error',
id : 'error-image',
not_append : true
});
return lE;
}
};
/**
* add class to current element
* @param pElement
* @param pClass
*/
DOM.addClass = function(pElement, pClass){
var lRet_b = true;
var lClassList = pElement.classList;
if(lClassList){
if( !lClassList.contains(pClass) )
lClassList.add(pClass);
else
lRet_b = false;
}
return lRet_b;
};
/**
* safe add event listener
* @param pType
* @param pListener
* @param pUseCapture
* @param pElement {document by default}
*/
DOM.addListener = function(pType, pListener, pUseCapture, pElement){
return (pElement || document).addEventListener(
pType,
pListener,
pUseCapture || false
);
};
/**
* safe add event keydown listener
* @param pListener
* @param pUseCapture
*/
DOM.addKeyListener = function(pListener, pUseCapture){
return DOM.addListener('keydown', pListener, pUseCapture);
};
/**
* load file countent thrue ajax
*/
DOM.ajax = function(pParams){
var lType = pParams.type || 'GET',
lData = pParams.data,
lSuccess_f = pParams.success;
if(!XMLHTTP)
XMLHTTP = new XMLHttpRequest();
XMLHTTP.open(lType, pParams.url, true);
XMLHTTP.send(lData);
if( !Util.isFunction(lSuccess_f) ){
console.log('error in DOM.ajax onSuccess:', pParams);
console.log(pParams);
}
XMLHTTP.onreadystatechange = function(pEvent){
if (XMLHTTP.readyState === 4 /* Complete */){
var lJqXHR = pEvent.target,
lType = XMLHTTP.getResponseHeader('content-type');
if (XMLHTTP.status === 200 /* OK */){
var lData = lJqXHR.response;
/* If it's json - parse it as json */
if(lType && Util.isContainStr(lType, 'application/json') ){
var lResult = Util.tryCatch(function(){
lData = JSON.parse(lJqXHR.response);
});
if( Util.log(lResult) )
lData = lJqXHR.response;
}
lSuccess_f(lData, lJqXHR.statusText, lJqXHR);
}
else/* file not found or connection lost */{
/* if html given or something like it
* getBack just status of result
*/
if(lType &&
lType.indexOf('text/plain') !== 0){
lJqXHR.responseText = lJqXHR.statusText;
}
Util.exec(pParams.error, lJqXHR);
}
}
};
};
/**
* Обьект для работы с кэшем
* в него будут включены функции для
* работы с LocalStorage, webdb,
* indexed db etc.
*/
DOM.Cache = function(){
/* приватный переключатель возможности работы с кэшем */
var CacheAllowed,
Data = {};
/* функция проверяет возможно ли работать с кэшем каким-либо образом */
this.isAllowed = function(){
return ( CacheAllowed = Util.isObject( window.localStorage ) );
};
/**
* allow cache usage
*/
this.setAllowed = function(){
var lRet = this;
CacheAllowed = true;
return lRet;
};
/**
* dissalow cache usage
*/
this.UnSetAllowed = function(){
var lRet = this;
CacheAllowed = false;
return lRet;
};
/** remove element */
this.remove = function(pItem){
var lRet = this;
if(CacheAllowed)
localStorage.removeItem(pItem);
return lRet;
};
/** если доступен localStorage и
* в нём есть нужная нам директория -
* записываем данные в него
*/
this.set = function(pName, pData){
var lRet = this;
if(CacheAllowed && pName && pData)
localStorage.setItem(pName,pData);
return lRet;
},
/** Если доступен Cache принимаем из него данные*/
this.get = function(pName){
var lRet = this;
if(CacheAllowed)
lRet = localStorage.getItem(pName);
return lRet;
},
/* get all cache from local storage */
this.getAll = function(){
var lRet = null;
if(CacheAllowed)
lRet = localStorage;
return lRet;
};
/** функция чистит весь кэш для всех каталогов*/
this.clear = function(){
var lRet = this;
if(CacheAllowed)
localStorage.clear();
return lRet;
};
};
DOM.Cache = new DOM.Cache();
/**
* Function gets id by src
* @param pSrc
*
* Example: http://domain.com/1.js -> 1_js
*/
DOM.getIdBySrc = function(pSrc){
var lID = pSrc.replace(pSrc.substr(pSrc,
pSrc.lastIndexOf('/')+1),
'');
/* убираем точки */
while(lID.indexOf('.') > 0)
lID = lID.replace('.','_');
return lID;
},
/**
* create elements and load them to DOM-tree
* one-by-one
*
* @param pParams_a
* @param pFunc - onload function
*/
DOM.anyLoadOnLoad = function(pParams_a, pFunc){
if( Util.isArray(pParams_a) ) {
var lParam = pParams_a.pop(),
lFunc = function(){
DOM.anyLoadOnLoad(pParams_a, pFunc);
};
if( Util.isString(lParam) )
lParam = { src : lParam };
else if( Util.isArray(lParam) ){
DOM.anyLoadInParallel(lParam, lFunc);
}
if(lParam && !lParam.func){
lParam.func = lFunc;
DOM.anyload(lParam);
}else
Util.exec(pFunc);
}
};
/**
* improve callback of funcs so
* we pop number of function and
* if it's last we call pCallBack
*
* @param pParams_a
* @param pFunc - onload function
*/
DOM.anyLoadInParallel = function(pParams_a, pFunc){
var lRet = Util.isArray(pParams_a),
done = [],
doneFunc = function (pCallBack){
Util.exec(pCallBack);
if( !done.pop() )
Util.exec(pFunc);
};
if(!lRet){
pParams_a = [pParams_a];
}
for(var i = 0, n = pParams_a.length; i < n; i++){
var lParam = pParams_a.pop();
if(lParam){
done.push(i);
if(Util.isString(lParam) )
lParam = { src : lParam };
var lFunc = lParam.func;
lParam.func = Util.retExec(doneFunc, lFunc);
DOM.anyload(lParam);
lRet = true;
}
}
return lRet;
};
/**
* Функция создаёт элемент и загружает файл с src.
*
* @param pParams_o = {
* name, - название тэга
* src', - путь к файлу
* func, - обьект, содержаий одну из функций
* или сразу две onload и onerror
* {onload: function(){}, onerror: function();}
* style,
* id,
* element,
* async, - true by default
* inner: 'id{color:red, },
* class,
* not_append - false by default
* }
*/
DOM.anyload = function(pParams_o){
if( !pParams_o ) return;
/* if a couple of params was
* processing every of params
* and quit
*/
if( Util.isArray(pParams_o) ){
var lElements_a = [];
for(var i = 0, n = pParams_o.length; i < n ; i++)
lElements_a[i] = DOM.anyload(pParams_o[i]);
return lElements_a;
}
var lName = pParams_o.name,
lID = pParams_o.id,
lClass = pParams_o.className,
lSrc = pParams_o.src,
lFunc = pParams_o.func,
lOnError,
lAsync = pParams_o.async,
lParent = pParams_o.parent,
lInner = pParams_o.inner,
lNotAppend = pParams_o.not_append;
if ( Util.isObject(lFunc) ){
lOnError = lFunc.onerror;
lFunc = lFunc.onload;
}
/* убираем путь к файлу, оставляя только название файла */
if(!lID && lSrc)
lID = DOM.getIdBySrc(lSrc);
var element = DOM.getById(lID);
/* если скрипт еще не загружен */
if(!element){
if(!lName && lSrc){
var lDot = lSrc.lastIndexOf('.'),
lExt = lSrc.substr(lDot);
switch(lExt){
case '.js':
lName = 'script';
break;
case '.css':
lName = 'link';
lParent = document.head;
break;
default:
return {code: -1, text: 'name can not be empty'};
}
}
element = document.createElement(lName);
if(lID)
element.id = lID;
if(lClass)
element.className = lClass;
/* if working with external css
* using href in any other case
* using src
*/
if(lName === 'link'){
element.href = lSrc;
element.rel = 'stylesheet';
}else
element.src = lSrc;
/*
* if passed arguments function
* then it's onload by default
*
* if object - then onload and onerror
*/
if( Util.isFunction(lFunc) )
element.onload = lFunc;
/* if element (js/css) will not loaded
* it would be removed from DOM tree
* and error image would be shown
*/
element.onerror = (function(){
(pParams_o.parent || document.body)
.removeChild(element);
DOM.Images.showError({
responseText: 'file ' +
lSrc +
' could not be loaded',
status : 404
});
Util.exec(lOnError);
});
if(pParams_o.style){
element.style.cssText = pParams_o.style;
}
if(lAsync || lAsync === undefined)
element.async = true;
if(!lNotAppend)
(lParent || document.body).appendChild(element);
if(lInner){
element.innerHTML = lInner;
}
}
/* если js-файл уже загружен
* запускаем функцию onload
*/
else
Util.exec(lFunc);
return element;
},
/**
* Функция загружает js-файл
*
* @param pSrc
* @param pFunc
*/
DOM.jsload = function(pSrc, pFunc){
if(pSrc instanceof Array){
for(var i=0; i < pSrc.length; i++)
pSrc[i].name = 'script';
return DOM.anyload(pSrc);
}
return DOM.anyload({
name : 'script',
src : pSrc,
func : pFunc
});
},
/**
* Функция создаёт елемент style и записывает туда стили
* @param pParams_o - структура параметров, заполняеться таким
* образом: {src: ' ',func: '', id: '', element: '', inner: ''}
* все параметры опциональны
*/
DOM.cssSet = function(pParams_o){
pParams_o.name = 'style';
pParams_o.parent = pParams_o.parent || document.head;
return DOM.anyload(pParams_o);
},
/**
* Function loads external css files
* @pParams_o - структура параметров, заполняеться таким
* образом: {src: ' ',func: '', id: '', element: '', inner: ''}
* все параметры опциональны
*/
DOM.cssLoad = function(pParams_o){
if( Util.isArray(pParams_o) ){
for(var i = 0, n = pParams_o.length; i < n; i++){
pParams_o[i].name = 'link';
pParams_o[i].parent = pParams_o.parent || document.head;
}
return DOM.anyload(pParams_o);
}
else if( Util.isString(pParams_o) )
pParams_o = { src: pParams_o };
pParams_o.name = 'link';
pParams_o.parent = pParams_o.parent || document.head;
return DOM.anyload(pParams_o);
};
/**
* load jquery from google cdn or local copy
* @param pCallBack
*/
DOM.jqueryLoad = function(pCallBack){
/* загружаем jquery: */
DOM.jsload('//ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min.js',{
onload: Util.retExec(pCallBack),
onerror: function(){
DOM.jsload('lib/client/jquery.js');
/*
* if could not load jquery from google server
* maybe we offline, load font from local
* directory
*/
DOM.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");}'
});
}
});
};
/**
* load socket.io
* @param pCallBack
*/
DOM.socketLoad = function(pCallBack){
DOM.jsload('lib/client/socket.js', pCallBack);
};
/* DOM */
/**
* Function search element by tag
* @param pTag - className
* @param pElement - element
*/
DOM.getByTag = function(pTag, pElement){
return (pElement || document).getElementsByTagName(pTag);
};
/**
* Function search element by id
* @param Id - className
* @param pElement - element
*/
DOM.getById = function(pId, pElement){
return (pElement || document).getElementById(pId);
};
/**
* Function search element by class name
* @param pClass - className
* @param pElement - element
*/
DOM.getByClass = function(pClass, pElement){
return (pElement || document).getElementsByClassName(pClass);
};
DOM.Images = {
/**
* Function shows loading spinner
* pPosition = {top: true};
*/
showLoad : function(pPosition){
var lRet_b = true;
LoadingImage = Images_o.loading();
ErrorImage = Images_o.error();
DOM.hide(ErrorImage);
var lCurrent;
if(pPosition){
if(pPosition.top){
lCurrent = DOM.getRefreshButton();
if(lCurrent)
lCurrent = lCurrent.parentElement;
else
lRet_b = false;
}
}
else{
lCurrent = DOM.getCurrentFile();
lCurrent = lCurrent.firstChild.nextSibling;
}
/* show loading icon
* if it not showed
* and if error was not
* heppen
*/
if(lRet_b){
var lParent = LoadingImage.parentElement;
if(!lParent ||
(lParent && lParent !== lCurrent))
lCurrent.appendChild(LoadingImage);
DOM.show(LoadingImage); /* показываем загрузку*/
}
return lRet_b;
},
/**
* hide load image
*/
hideLoad : function(){
LoadingImage = Images_o.loading();
DOM.hide(LoadingImage);
},
/**
* show error image (usualy after error on ajax request)
*/
showError : function(jqXHR, textStatus, errorThrown){
LoadingImage = Images_o.loading();
ErrorImage = Images_o.error();
var lText;
if(jqXHR.status === 404)
lText = jqXHR.responseText;
else
lText = jqXHR.statusText;
/* если файла не существует*/
if(!lText.indexOf('Error: ENOENT, '))
lText = lText.replace('Error: ENOENT, n','N');
/* если не хватает прав для чтения файла*/
else if(!lText.indexOf('Error: EACCES,'))
lText = lText.replace('Error: EACCES, p','P');
DOM.show(ErrorImage);
ErrorImage.title = lText;
var lParent = LoadingImage.parentElement;
if(lParent)
lParent.appendChild(ErrorImage);
DOM.hide(LoadingImage);
console.log(lText);
}
};
/**
* unified way to get current file
*/
DOM.getCurrentFile = function(){
var lCurrent = DOM.getByClass(getCurrentFile())[0];
if(!lCurrent)
DOM.addCloudStatus({
code : -1,
msg : 'Error: can not find ' +
'CurrentFile ' +
'in getCurrentFile'
});
return lCurrent;
};
/**
* unified way to get RefreshButton
*/
DOM.getRefreshButton = function(){
var lPanel = DOM.getPanel(),
lRefresh = DOM.getByClass(CloudFunc.REFRESHICON, lPanel);
if (lRefresh.length)
lRefresh = lRefresh[0];
else {
DOM.addCloudStatus({
code : -3,
msg : 'Error Refresh icon not found'
});
lRefresh = false;
}
return lRefresh;
};
/**
* unified way to set current file
*/
DOM.setCurrentFile = function(pCurrentFile){
var lRet_b = true;
if(!pCurrentFile){
DOM.addCloudStatus({
code : -1,
msg : 'Error pCurrentFile in' +
'setCurrentFile' +
'could not be none'
});
lRet_b = false;
}
var lCurrentFileWas = DOM.getCurrentFile();
if (pCurrentFile.className === 'path')
pCurrentFile = pCurrentFile.nextSibling;
if (pCurrentFile.className === 'fm_header')
pCurrentFile = pCurrentFile.nextSibling;
if(lCurrentFileWas)
UnSetCurrentFile(lCurrentFileWas);
DOM.addClass(pCurrentFile, getCurrentFile());
/* scrolling to current file */
DOM.scrollIntoViewIfNeeded(pCurrentFile);
return lRet_b;
};
/**
* set onclick handler on buttons f1-f10
* @param pKey - 'f1'-'f10'
*/
DOM.setButtonKey = function(pKey, pFunc){
return CloudCommander.KeysPanel[pKey].onclick = pFunc;
};
/**
* current file check
*
* @param pCurrentFile
*/
DOM.isCurrentFile = function(pCurrentFile){
if(!pCurrentFile)
DOM.addCloudStatus({
code : -1,
msg : 'Error pCurrentFile in' +
'isCurrentFile' +
'could not be none'
});
var lCurrentFileClass = pCurrentFile.className,
lIsCurrent = lCurrentFileClass.indexOf(getCurrentFile()) >= 0;
return lIsCurrent;
};
/**
* get link from current (or param) file
*
* @param pCurrentFile - current file by default
*/
DOM.getCurrentLink = function(pCurrentFile){
var lLink = DOM.getByTag('a',
pCurrentFile || DOM.getCurrentFile()),
lRet = lLink.length > 0 ? lLink[0] : -1;
if(!lRet)
DOM.addCloudStatus({
code : -1,
msg : 'Error current element do not contain links'
});
return lRet;
};
/**
* get name from current (or param) file
*
* @param pCurrentFile
*/
DOM.getCurrentName = function(pCurrentFile){
var lLink = DOM.getCurrentLink(
pCurrentFile || DOM.getCurrentFile());
if(!lLink)
DOM.addCloudStatus({
code : -1,
msg : 'Error current element do not contain links'
});
else lLink = lLink.textContent;
return lLink;
};
/** function getting FM
* @param pPanel_o = {active: true}
*/
DOM.getFM = function(){
return DOM.getPanel().parentElement;
};
/** function getting panel active, or passive
* @param pPanel_o = {active: true}
*/
DOM.getPanel = function(pActive){
var lPanel = DOM.getCurrentFile().parentElement;
/* if {active : false} getting passive panel */
if(pActive && !pActive.active){
var lId = lPanel.id === 'left' ? 'right' : 'left';
lPanel = DOM.getById(lId);
}
/* if two panels showed
* then always work with passive
* panel
*/
if(window.innerWidth < CloudCommander.MIN_ONE_PANEL_WIDTH)
lPanel = DOM.getById('left');
if(!lPanel)
console.log('Error can not find Active Panel');
return lPanel;
};
DOM.show = function(pElement){
DOM.removeClass(pElement, 'hidden');
};
/**
* shows panel right or left (or active)
*/
DOM.showPanel = function(pActive){
var lRet = true,
lPanel = DOM.getPanel(pActive);
if(lPanel)
DOM.show(lPanel);
else
lRet = false;
return lRet;
};
/**
* hides panel right or left (or active)
*/
DOM.hidePanel = function(pActive){
var lRet = false,
lPanel = DOM.getPanel(pActive);
if(lPanel)
lRet = DOM.hide(lPanel);
return lRet;
};
/**
* add class=hidden to element
*
* @param pElement
*/
DOM.hide = function(pElement){
return DOM.addClass(pElement, 'hidden');
};
/**
* remove child of element
* @param pChild
* @param pElement
*/
DOM.remove = function(pChild, pElement){
return (pElement || document.body).removeChild(pChild);
};
/**
* remove class pClass from element pElement
* @param pElement
* @param pClass
*/
DOM.removeClass = function(pElement, pClass){
var lRet_b = true,
lClassList = pElement.classList;
if(pElement && lClassList)
lClassList.remove(pClass);
else
lRet_b = false;
return lRet_b;
};
/**
* remove current file from file table
* @pCurrent
*/
DOM.removeCurrent = function(pCurrent){
var lParent = pCurrent.parentElement;
if(!pCurrent)
pCurrent = DOM.getCurrentFile();
var lName = DOM.getCurrentName(pCurrent);
if(pCurrent && lParent){
if(lName !== '..'){
var lNext = pCurrent.nextSibling;
var lPrevious = pCurrent.previousSibling;
if(lNext)
DOM.setCurrentFile(lNext);
else if(lPrevious)
DOM.setCurrentFile(lPrevious);
lParent.removeChild(pCurrent);
}
else
DOM.addCloudStatus({
code : -1,
msg : 'Could not remove parrent dir'
});
}
else
DOM.addCloudStatus({
code : -1,
msg : 'Current file (or parent of current) could not be empty'
});
return pCurrent;
};
/**
* unified way to scrollIntoViewIfNeeded
* (native suporte by webkit only)
* @param pElement
*/
DOM.scrollIntoViewIfNeeded = function(pElement){
var lRet = true;
if(pElement && pElement.scrollIntoViewIfNeeded)
pElement.scrollIntoViewIfNeeded();
else
lRet = false;
return lRet;
};
/**
* function gets time
*/
DOM.getTime = function(){
var date = new Date(),
hours = date.getHours(),
minutes = date.getMinutes(),
seconds = date.getSeconds();
minutes = minutes < 10 ? '0' + minutes : minutes;
seconds = seconds < 10 ? '0' + seconds : seconds;
return hours + ":" + minutes + ":" + seconds;
};
/**
* array of all statuses of opertattions
*/
DOM.CloudStatus = [];
/**
* adds status of operation
* @param pStatus
*/
DOM.addCloudStatus = function(pStatus){
DOM.CloudStatus[DOM.CloudStatus.length] = pStatus;
};
})();