/**
* Расширение типов ячеек dhtmlXGrid
*
* © Evgeniy Malyarov http://www.oknosoft.ru 2014-2016
*
* Экспортирует конструкторы:
* * **eXcell_ref** - поля ввода значений ссылочных типов
* * **eXcell_refc** - комбобокс ссылочных типов (перечисления и короткие справочники)
*
* @module wdg_dhtmlx
* @requires common
*/
// Прототип кустомных ячеек для грида
var eXcell_proto = new eXcell();
/**
* Обработчик клавиш {tab}, {enter} и {F4} в поле ввода
*/
eXcell_proto.input_keydown = function(e, t){
function obj_on_select(v){
if(t.source.on_select)
t.source.on_select.call(t.source, v);
}
if(e.keyCode === 8 || e.keyCode === 46){ // по {del} и {bs} очищаем значение
t.setValue("");
t.grid.editStop();
if(t.source.on_select)
t.source.on_select.call(t.source, "");
}else if(e.keyCode === 9 || e.keyCode === 13)
t.grid.editStop(); // по {tab} и {enter} заканчиваем редактирование
else if(e.keyCode === 115)
t.cell.firstChild.childNodes[1].onclick(e); // по {F4} открываем редактор
else if(e.keyCode === 113){ // по {F2} открываем форму объекта
if(t.source.tabular_section){
t.mgr = _md.value_mgr(t.source.row, t.source.col, t.source.row._metadata.fields[t.source.col].type);
if(t.mgr){
var tv = t.source.row[t.source.col];
t.mgr.form_obj(t.source.wnd, {
o: tv,
on_select: obj_on_select
});
}
}else if(t.fpath.length==1){
t.mgr = _md.value_mgr(t.source.o._obj, t.fpath[0], t.source.o._metadata.fields[t.fpath[0]].type);
if(t.mgr){
var tv = t.source.o[t.fpath[0]];
t.mgr.form_obj(t.source.wnd, {
o: tv,
on_select: obj_on_select
});
}
}
}
return $p.iface.cancel_bubble(e);
};
/**
* Конструктор поля ввода со списком OCombo
* @param cell
*/
function eXcell_ocombo(cell){
if (!cell)
return;
var t = this;
t.cell = cell;
t.grid = cell.parentNode.grid;
/**
* устанавливает текст в ячейке. например, this.setCValue("<input type='button' value='"+val+"'>",val);
*/
t.setValue=function(val){
t.setCValue(val instanceof DataObj ? val.presentation : (val || ""));
};
/**
* получает значение ячейки из табличной части или поля объекта или допполя допобъекта, а не из грида
*/
t.getValue=function(){
return t.grid.get_cell_value();
};
/**
* Обрабатывает событие перехода к следующему полю (окончание редактирования)
*/
t.shiftNext = function () {
t.grid.editStop();
};
/**
* Cоздаёт элементы управления редактора и назначает им обработчики
*/
t.edit=function(){
if(t.combo)
return;
t.val = t.getValue(); //save current value
t.cell.innerHTML = "";
t.combo = new OCombo({
parent: t.cell
}._mixin(t.grid.get_cell_field()));
t.combo.getInput().focus();
};
/**
* вызывается при отключении редактора
* @return {boolean} - если "истина", значит объект был изменён
*/
t.detach=function(){
if(t.combo){
if(t.combo.getComboText){
t.setValue(t.combo.getComboText()); // текст в элементе управления
if(!t.combo.getSelectedValue())
t.combo.callEvent("onChange");
var res = !$p.utils.is_equal(t.val, t.getValue());// compares the new and the old values
t.combo.unload();
return res;
} else if(t.combo.unload){
t.combo.unload();
}
}
return true;
}
}
eXcell_ocombo.prototype = eXcell_proto;
window.eXcell_ocombo = eXcell_ocombo;
/**
* Конструктор поля ввода значений ссылочных типов для грида
* @param cell
*/
window.eXcell_ref = eXcell_ocombo;
/**
* Конструктор комбобокса кешируемых ссылочных типов для грида
*/
window.eXcell_refc = eXcell_ocombo;
/**
* Конструктор поля пароля
*/
function eXcell_pwd(cell){ //the eXcell name is defined here
var fnedit;
if (cell){ //the default pattern, just copy it
this.cell = cell;
this.grid = cell.parentNode.grid;
eXcell_ed.call(this); //uses methods of the "ed" type
fnedit = this.edit;
this.edit = function(){
fnedit.call(this);
this.obj.type="password";
};
this.setValue=function(){
this.setCValue("*********");
};
this.getValue=function(){
return this.grid.get_cell_value();
};
this.detach=function(){
if(this.grid.get_cell_field){
var cf = this.grid.get_cell_field();
cf.obj[cf.field] = this.obj.value;
}
this.setValue();
fnedit = null;
return this.val != this.getValue();
}
}
}
eXcell_pwd.prototype = eXcell_proto;
window.eXcell_pwd = eXcell_pwd;
dhtmlXCalendarObject.prototype._dateToStr = function(val, format) {
if(val instanceof Date && val.getFullYear() < 1000)
return "";
else
return window.dhx4.date2str(val, format||this._dateFormat, this._dateStrings());
};
eXcell_dhxCalendar.prototype.edit = function() {
var arPos = this.grid.getPosition(this.cell);
this.grid._grid_calendarA._show(false, false);
this.grid._grid_calendarA.setPosition(arPos[0],arPos[1]+this.cell.offsetHeight);
this.grid._grid_calendarA._last_operation_calendar = false;
this.grid.callEvent("onCalendarShow", [this.grid._grid_calendarA, this.cell.parentNode.idd, this.cell._cellIndex]);
this.cell._cediton = true;
this.val = this.cell.val;
if(this.val instanceof Date && this.val.getFullYear() < 1000)
this.val = new Date();
this._val = this.cell.innerHTML;
var t = this.grid._grid_calendarA.draw;
this.grid._grid_calendarA.draw = function(){};
this.grid._grid_calendarA.setDateFormat((this.grid._dtmask||"%d.%m.%Y"));
this.grid._grid_calendarA.setDate(this.val||(new Date()));
this.grid._grid_calendarA.draw = t;
};
/**
* fix ajax
*/
(function(){
function fix_auth(t, method, url, async){
if(url.indexOf("odata/standard.odata") != -1 || url.indexOf("/hs/rest") != -1){
var username, password;
if($p.ajax.authorized){
username = $p.ajax.username;
password = $p.aes.Ctr.decrypt($p.ajax.password);
}else{
if($p.job_prm.guest_name){
username = $p.job_prm.guest_name;
password = $p.aes.Ctr.decrypt($p.job_prm.guest_pwd);
}else{
username = $p.wsql.get_user_param("user_name");
password = $p.aes.Ctr.decrypt($p.wsql.get_user_param("user_pwd"));
}
}
t.open(method, url, async, username, password);
t.withCredentials = true;
t.setRequestHeader("Authorization", "Basic " +
btoa(unescape(encodeURIComponent(username + ":" + password))));
}else
t.open(method, url, async);
}
dhx4.ajax._call = function(method, url, postData, async, onLoad, longParams, headers) {
var t = (window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP"));
var isQt = (navigator.userAgent.match(/AppleWebKit/) != null && navigator.userAgent.match(/Qt/) != null && navigator.userAgent.match(/Safari/) != null);
if (async == true) {
t.onreadystatechange = function() {
if ((t.readyState == 4) || (isQt == true && t.readyState == 3)) { // what for long response and status 404?
if (t.status != 200 || t.responseText == "")
if (!dhx4.callEvent("onAjaxError", [{xmlDoc:t, filePath:url, async:async}])) return;
window.setTimeout(function(){
if (typeof(onLoad) == "function") {
onLoad.apply(window, [{xmlDoc:t, filePath:url, async:async}]); // dhtmlx-compat, response.xmlDoc.responseXML/responseText
}
if (longParams != null) {
if (typeof(longParams.postData) != "undefined") {
dhx4.ajax.postLong(longParams.url, longParams.postData, onLoad);
} else {
dhx4.ajax.getLong(longParams.url, onLoad);
}
}
onLoad = null;
t = null;
},1);
}
}
}
if (method == "GET") {
url += this._dhxr(url);
}
t.open(method, url, async);
// если обращение по rest или irest, добавляем авторизацию
fix_auth(t, method, url, async);
if (headers != null) {
for (var key in headers) t.setRequestHeader(key, headers[key]);
} else if (method == "POST" || method == "PUT" || method == "DELETE") {
t.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
} else if (method == "GET") {
postData = null;
}
t.setRequestHeader("X-Requested-With", "XMLHttpRequest");
t.send(postData);
if (async != true) {
if ((t.readyState == 4) || (isQt == true && t.readyState == 3)) {
if (t.status != 200 || t.responseText == "") dhx4.callEvent("onAjaxError", [{xmlDoc:t, filePath:url, async:async}]);
}
}
return {xmlDoc:t, filePath:url, async:async}; // dhtmlx-compat, response.xmlDoc.responseXML/responseText
};
dhtmlx.ajax.prototype.send = function(url,params,call){
var x=this.getXHR();
if (typeof call == "function")
call = [call];
//add extra params to the url
if (typeof params == "object"){
var t=[];
for (var a in params){
var value = params[a];
if (value === null || value === dhtmlx.undefined)
value = "";
t.push(a+"="+encodeURIComponent(value));// utf-8 escaping
}
params=t.join("&");
}
if (params && !this.post){
url=url+(url.indexOf("?")!=-1 ? "&" : "?")+params;
params=null;
}
//x.open(this.post?"POST":"GET",url,!this._sync);
fix_auth(x, this.post?"POST":"GET",url,!this._sync);
if (this.post)
x.setRequestHeader('Content-type','application/x-www-form-urlencoded');
//async mode, define loading callback
//if (!this._sync){
var self=this;
x.onreadystatechange= function(){
if (!x.readyState || x.readyState == 4){
//dhtmlx.log_full_time("data_loading"); //log rendering time
if (call && self)
for (var i=0; i < call.length; i++) //there can be multiple callbacks
if (call[i])
call[i].call((self.master||self),x.responseText,x.responseXML,x);
self.master=null;
call=self=null; //anti-leak
}
};
//}
x.send(params||null);
return x; //return XHR, which can be used in case of sync. mode
}
})();
/**
* Проверяет, видна ли ячейка
* TODO: учесть слой, модальность и т.д.
*/
dhtmlXCellObject.prototype.is_visible = function () {
var rect = this.cell.getBoundingClientRect();
return rect.right > 0 && rect.bottom > 0;
};
$p.iface.data_to_grid = function (data, attr){
if(this.data_to_grid)
return this.data_to_grid(data, attr);
function cat_picture_class(r){
var res;
if(r.hasOwnProperty("posted")){
res = r.posted ? "cell_doc_posted" : "cell_doc";
}else{
res = r.is_folder ? "cell_ref_folder" : "cell_ref_elm";
}
if(r._deleted)
res = res + "_deleted";
return res ;
}
function do_format(v){
if(v instanceof Date){
if(v.getHours() || v.getMinutes())
return $p.moment(v).format($p.moment._masks.date_time);
else
return $p.moment(v).format($p.moment._masks.date);
}else
return typeof v == "number" ? v : $p.iface.normalize_xml(v || "");
}
var xml = "<?xml version='1.0' encoding='UTF-8'?><rows total_count='%1' pos='%2' set_parent='%3'>"
.replace("%1", attr._total_count || data.length).replace("%2", attr.start)
.replace("%3", attr.set_parent || "" ),
caption = this.caption_flds(attr);
// при первом обращении к методу добавляем описание колонок
xml += caption.head;
data.forEach(function(r){
xml += "<row id=\"" + r.ref + "\"><cell class=\"" + cat_picture_class(r) + "\">" + do_format(r[caption.acols[0].id]) + "</cell>";
for(var col=1; col < caption.acols.length; col++ )
xml += "<cell>" + do_format(r[caption.acols[col].id]) + "</cell>";
xml += "</row>";
});
return xml + "</rows>";
};
/**
* Создаёт иерархический объект для построения dhtmlxTreeView
* @param data
* @return {*[]}
*/
$p.iface.data_to_tree = function (data) {
var res = [{id: $p.utils.blank.guid, text: "..."}];
function add_hierarchically(arr, row){
var curr = {id: row.ref, text: row.presentation, items: []};
arr.push(curr);
$p._find_rows(data, {parent: row.ref}, function(r){
add_hierarchically(curr.items, r);
});
if(!curr.items.length)
delete curr.items;
}
$p._find_rows(data, {parent: $p.utils.blank.guid}, function(r){
add_hierarchically(res, r);
});
return res;
};