Javascript-форум (https://javascript.ru/forum/)
-   Элементы интерфейса (https://javascript.ru/forum/dom-window/)
-   -   Электронные таблицы на JS (https://javascript.ru/forum/dom-window/1674-ehlektronnye-tablicy-na-js.html)

gagagogo 01.09.2008 18:08

Электронные таблицы на JS
 
Здравствуйте!
Хочу сделать нечто вроде экселевской таблицы на JavaScript. Я сделал её, но работает медленно. Если взять таблицу размером (800х14) то её загрузка в IE требует 29 секунд. Я недоволен. Не хочется изобретать велосипед, может ктото делал такую вещь? Посоветуйте что нибудь. Могу скинуть свой код, там 205 строк.

ZoNT 01.09.2008 18:57

скинь, мне интересно.

У меня генерация таблицы 800*14 в ФФ2 занимает 2100миллисекунды (визуально 3).

Kolyaj 01.09.2008 19:24

Сам не реализовывал, поэтому по слухам: большие таблицы сильно тормозят (в ИЕ?). Вариант решения: разбивать на много маленьких таблиц, следующих друг за другом.

ZoNT 01.09.2008 20:24

Большик таблицы просто жесть как тормозят в ИЕ, но также они тормозят в Сафари (но меньше), потом идёт ФФ, и почти не тормозят в Опере (но в опере вылазит куча других проблем)...

gagagogo 02.09.2008 09:33

вот мой код
/*
SpreadSheet.js
*/
Array.prototype.search = function(search){
	var i=0;while(this[i++]!=search && i<this.length);
	return this[i-1]!=search?false:i-1;
};

/*
ЯЧЕЙКА ТАБЛИЦИ
*/
function cell(){
	this.r = 0;
	this.c = 0;
	this.parent = null;
	this.value = '';
	this.borderColor = '#7F9DB9';
	this.borderWidth = '1';
	this.defaultStyle = function(){
		this.borderColor = '#7F9DB9';
		this.borderWidth = '1';
	};
	this.activeStyle = function(){
		this.borderColor = '#000000';
		this.borderWidth = '3';
	};
	this.setAutoCompleter = function(url){
		/*var td = this.findTableCell(this.r,this.c);
		var input = td.getElementsByTagName('INPUT')[0];
		var acDiv = document.createElement("DIV");
		acDiv.className = 'ac';
		td.appendChild(acDiv);
		this.AutoCompleter = new AutoCompleter(acDiv,input,url);
		_onkeydown = input.onkeydown;
		input.onkeydown = function(e){
			if('block' == acDiv.style.display){}
			else {_onkeydown();}
		};*/
	};
	this.findTableCell = function(r,c){
		var t = this.parent._obj.getElementsByTagName('TABLE');
		return t[t.length-1].getElementsByTagName('TR')[this.r-1].getElementsByTagName('TD')[this.c-1];
	};
}
/*
ТАБЛИЦА
*/
function sheet(obj){
	return {
		row:1,
		col:1,
		cells:[], // хеш массив ячеек
		_obj:obj,
		cell:function(r,c){
			var rCount=0,cCount=0;
			while(this.cells.length < r){
				this.cells.push([]);
				rCount = this.cells.length - 1;
				while(this.cells[rCount].length < c){
					this.cells[rCount].push(new cell());
					cCount = this.cells[rCount].length - 1;
					this.cells[rCount][cCount].r = rCount+1;
					this.cells[rCount][cCount].c = cCount+1;
					this.cells[rCount][cCount].parent = this;
				}
			}
			return this.cells[r-1][c-1];
		},
		moveTo:function(r,c){
			if(r<1 || c<1 || r>this.cells.length || c>this.cells[0].length)
			return;
			with(this){
				cell(this.row,this.col).defaultStyle();
				cell(r,c).activeStyle();
				updateCell(this.row,this.col);
				updateCell(r,c);
				row=r;
				col=c;
			}
		},
		updateCell:function(r,c){
			var t = obj.getElementsByTagName('TABLE');
			row   = t[t.length-1].getElementsByTagName('TR')[r-1];
			cell  = row.cells[c-1];
			input = cell.getElementsByTagName('INPUT')[0];
			input.style.borderWidth = this.cell(r,c).borderWidth;
			input.style.borderColor = this.cell(r,c).borderColor;
			if(''!=input.value && input.value!=this.cell(r,c).value)
			this.cell(r,c).value = input.value;
			input.value = this.cell(r,c).value;
			input.focus();
		},
		show:function(){
			t = [];
			currenCell = {};
			t.push('<div></div><br><div><table border="0">');
			rCount = this.cells.length;
			cCount = this.cells[0].length;
			var tt= this
			var OnKeyDown = function(e){
				switch( keyCode(e) ){
					case 37: tt.moveTo(tt.row,tt.col-1); break;  // move left
					case 38: tt.moveTo(tt.row-1,tt.col); break;  // move up
					case 39: tt.moveTo(tt.row,tt.col+1); break;  // move right
					case 40: tt.moveTo(tt.row+1,tt.col); break;  // move down
				}
			};

			for(r=0; r<rCount; r++){
				t.push('<tr>');
				for(c=0; c<cCount; c++){
					currenCell = this.cells[r][c];
					t.push('<td><input autocomplete="off" style="width:100%;border:'+ currenCell.borderWidth +'px '+currenCell.borderColor+' solid" value="'  + currenCell.value +  '"></td>');
				}
				t.push('</tr>');
			}
			t.push('</table></div>');
			obj.innerHTML = t.join("\n");
			var inputs = obj.getElementsByTagName('INPUT');
			var inpCount = inputs.length;
			for(i=0;i<inpCount;i++){
				inputs[i].onclick= function(){
					c = this.parentNode.cellIndex +1;
					r = this.parentNode.parentNode.rowIndex +1;
					tt.moveTo(r,c);
				};
				inputs[i].onkeydown = OnKeyDown;
			}/**/
			window.onunload = function(){tt.cleanUp(tt)};
		},
		addHeaders:function(labelsList){ // labelList format: {name1:isSortable,name2:isSortable}
			var labels = [],h = [];
			for(key in labelsList)
			labels.push({name:key,isSortable:labelsList[key]});
			var rCount = this.cells[0].length;

			var t  = this._obj.getElementsByTagName('DIV')[0];
			var tw = this._obj.getElementsByTagName('TABLE')[0].clientWidth;

			var dt = this._obj.getElementsByTagName('TABLE')[0].getElementsByTagName('TR');

			h.push('<table cellspacing="0" cellpadding="0"><tr>');
			var v,options=[];
			for(i=0;i<rCount;i++){
				h.push('<td>');
				if(i<labels.length){
					if(labels[i].isSortable){
						h.push('<select style="background:#99CCFF;">');
						h.push('<option>'+labels[i].name+'</option>');
						for(j=0;j<this.cells.length;j++){
							if(false===options.search(this.cells[j][i].value) && ''!=this.cells[j][i].value){
								options.push(this.cells[j][i].value);
							}
						}
						for(j=0;j<options.length;j++)
						h.push('<option value="'+options[j]+'">'+options[j]+'</option>');
						options=[];
						h.push('</select>');
					}else
					h.push(labels[i].name);
				}else{h.push('&nbsp;')}
				h.push('</td>');
			}
			h.push('</tr></table>');
			t.innerHTML = h.join("\n");
			h = this._obj.getElementsByTagName('TABLE')[0].getElementsByTagName('TR')[0].getElementsByTagName('TD');
			t = this._obj.getElementsByTagName('TABLE')[1].getElementsByTagName('TR')[0].getElementsByTagName('TD');

			this._obj.getElementsByTagName('TABLE')[1].style.width = this._obj.getElementsByTagName('TABLE')[0].clientWidth;

			for(i=0;i<h.length;i++)
			t[i].style.width = h[i].clientWidth;
		},
		getValueList:function(collIndex){
			var list = [],v;
			for(i=0;i<this.cells.length;i++){
				if(!list.toString().match(this.cells[i][collIndex].value)){
					v = this.cells[i][collIndex].value;
					list.push('<option value="' + v +'">' + v + '</option>');
				}
			}
			return list.join('');
		},
		cleanUp:function(tt){
			// избегаем утечку памяти в Microsoft Internet Explorer
			for(i=0;i<tt.cells.length;i++){
				for(j=0;j<tt.cells[0].length;j++){
					tt.cells[i][j].parent=null;
					if(tt.cells[i][j].AutoCompleter){
						tt.cells[i][j].AutoCompleter = null;
					}
				}
			}
			var inp = document.getElementsByTagName('INPUT');
			for(l=0;l<inp.length;l++){
				inp[l].onclick 	 = null;
				inp[l].onkeydown = null;
			}
		}
	};
}
function keyCode(e){
	if (window.event) return window.event.keyCode;
	else if (e) return e.which;
}


так его запускать

<html>
	<head>
	<!--<link type="text/css" href="style.css" rel="stylesheet">-->
	<!--<script type="text/javascript" src="java.js"></script>-->
	</head>
	<body>
		<!-- ЭЛЕКТРОННАЯ ТАБЛИЦА-->
		<script type="text/javascript" src="SpreadSheet.js"></script>
		<div id="SpreadSheet" align="center">
			
		</div>
		<script>
			var b = new Date();
			var s = new sheet(document.getElementById('SpreadSheet'));
			s.cell(800,14);
						s.show();
//			s.cell(1,1).value = '11';
			//s.updateCell(1,1);
			//s.moveTo(1,1);
			//s.cell(305,14);
			//s.cell(1,1).setAutoCompleter('../helpdesk/trunk/ajaxDispecher.php?name=street');
			s.addHeaders({'Адрес установки':1,'Дом':1,'Под':1,'Switch':1,'IP адрес':1,'serial sw':1,'модуль':1,'1 модуль':1,'2 модуль':1,'Заказан':1,'Подготовлен':1,'Выдан':1,'Установлен':1,'Пометки':1});
			var e = new Date();
			alert((e.getTime() - b.getTime())/1000);
		</script>
		
		<!-- КОНЕЦ ЭЛЕКТРОННОЙ ТАБЛИЦИ-->
	</body>
</html>

ZoNT 02.09.2008 09:55

жесть... updateCell тормозная функция 117 милисекунд выполняется... с учётом того, что на одно передвижение она вызывается 2 раза получаются визуальные тормоза...

После профилировки обнаружил, что addHeaders занимает больше времени при создании таблицы, чем show :)

Оптимизировать и оптимизировать...

Советы:
- избавиться от всех getElementsByTagName (снести в инициализацию, одни раз их сделать, записать в свойства объекта "Электронная Таблица")
- не использовать .push, а использовать [index] = ...
- ты при генерации таблицы делаешь t.innerHTML = h.join("\n"); Я не помещаю строки в массив, а формирую сразу строку. В итоге получается быстрее, чем у тебя (хоть тесты и говорят, что в массив быстрее)...

gagagogo 02.09.2008 12:53

ZoNT, спасибо за советы. Как думаешь если оптимизировать можно в 2 секунды уложиться ? Или может лучше сгенерировать таблицу на php, а к ней уже обработчики событий прикрутить? Или может лучше вообще отказаться от этой затеи и написать на java аплет? Если у тебя есть можеш свой вариант скинуть ?

ZoNT 02.09.2008 12:54

Немного ускорил.
Но структура бредовая...
1) Зачем в каждую ячейку пихать инпут?
2) Зачем на каждый инпут(ячейку) вешать обработчик событий?

/*
SpreadSheet.js
*/
Array.prototype.search = function(search){
	for(var i=0,l=this.length;i<l;i++)if(this[i]==search)return i;
	return false;
}
 
/*
ЯЧЕЙКА ТАБЛИЦИ
*/
function cell(){
    this.r = 0;
    this.c = 0;
    this.parent = null;
    this.value = '';
    this.borderColor = '#7F9DB9';
    this.borderWidth = '1';
    this.defaultStyle = function(){
        this.borderColor = '#7F9DB9';
        this.borderWidth = '1';
    }
    this.activeStyle = function(){
        this.borderColor = '#000000';
        this.borderWidth = '3';
    }
    this.setAutoCompleter = function(url){}
    this.findTableCell = function(r,c){
        var t = this.parent._obj.getElementsByTagName('TABLE');
        return t[t.length-1].getElementsByTagName('TR')[this.r-1].getElementsByTagName('TD')[this.c-1];
    }
}
/*
ТАБЛИЦА
*/
function sheet(obj){
    return {
        row:1,
        col:1,
        cells:[], // хеш массив ячеек
        _obj:obj,
        cell:function(r,c){
            var rCount=0,cCount=0;
            while(this.cells.length < r){
                this.cells.push([]);
                rCount = this.cells.length - 1;
                while(this.cells[rCount].length < c){
                    this.cells[rCount].push(new cell());
                    cCount = this.cells[rCount].length - 1;
                    this.cells[rCount][cCount].r = rCount+1;
                    this.cells[rCount][cCount].c = cCount+1;
                    this.cells[rCount][cCount].parent = this;
                }
            }
            return this.cells[r-1][c-1];
        },
        moveTo:function(r,c){
            if(r<1 || c<1 || r>this.cells.length || c>this.cells[0].length)
            return;
            with(this){
                cell(this.row,this.col).defaultStyle();
                cell(r,c).activeStyle();
                updateCell(this.row,this.col);
                updateCell(r,c);
                row=r;
                col=c;
            }
        },
        updateCell:function(r,c){
            var input = this.Table.rows[r-1].cells[c-1].firstChild;
			var C = this.cell(r,c);
            input.style.borderWidth = C.borderWidth;
            input.style.borderColor = C.borderColor;
            if(''!=input.value && input.value!=C.value)
				C.value = input.value;
            input.value = C.value;
            input.focus();
        },
        show:function(){
            var t=[],i=0,currenCell;
            t[i++] = '<table border="0">';
            var rCount = this.cells.length;
            var cCount = this.cells[0].length;
            var tt = this;
            var OnKeyDown = function(e){
				e=e||event;
                switch(e.keyCode||e.charCode){
                    case 37: tt.moveTo(tt.row,tt.col-1); break;  // move left
                    case 38: tt.moveTo(tt.row-1,tt.col); break;  // move up
                    case 39: tt.moveTo(tt.row,tt.col+1); break;  // move right
                    case 40: tt.moveTo(tt.row+1,tt.col); break;  // move down
                }
            }
 
			t[i++] = '<tr>';
			var h = this.Header.rows[0];
			for(var c=0; c<cCount; c++){
				currenCell = this.cells[0][c];
				t[i++] = '<td style="width:'+h.cells[c].offsetWidth+'px;"><input autocomplete="off" style="width:100%;border:'+ currenCell.borderWidth +'px '+currenCell.borderColor+' solid" value="'  + currenCell.value +  '"></td>';
			}
			t[i++] = '</tr>';
			
            for(var r=1; r<rCount; r++){
                t[i++] = '<tr>';
                for(var c=0; c<cCount; c++){
                    currenCell = this.cells[r][c];
                    t[i++] = '<td><input autocomplete="off" style="width:100%;border:'+ currenCell.borderWidth +'px '+currenCell.borderColor+' solid" value="'  + currenCell.value +  '"></td>';
                }
                t[i++] = '</tr>';
            }
            t[i++] = '</table>';
            this._obj.lastChild.innerHTML = t.join("");
			
			this.Table = this._obj.lastChild.firstChild;
			this.Table.style.width = this.Header.offsetWidth;
			
            var inputs = this._obj.getElementsByTagName('INPUT');
            var inpCount = inputs.length;
            for(var i=0;i<inpCount;i++){
                inputs[i].onclick= function(){
                    c = this.parentNode.cellIndex +1;
                    r = this.parentNode.parentNode.rowIndex +1;
                    tt.moveTo(r,c);
                };
                inputs[i].onkeydown = OnKeyDown;
            }
            window.onunload = function(){tt.cleanUp(tt)};
        },
        addHeaders:function(labelsList){ // labelList format: {name1:isSortable,name2:isSortable}
            var labels = [],h = [],k=0;
            for(var key in labelsList)
				labels.push({name:key,isSortable:labelsList[key]});
				
            var rCount = this.cells[0].length;
			var cCount = this.cells.length;
 
            var t = this._obj;
			
            h[k++] = '<div><table cellspacing="0" cellpadding="0"><tr>';
			
            for(var i=0;i<rCount;i++){
                h[k++] = '<td>';
                if(i<labels.length){
                    if(labels[i].isSortable){
						h[k++] = '<select style="background:#99CCFF;"><option>'+labels[i].name+'</option>';
						
						var options=[];
                        for(var j=0;j<cCount;j++){
							var v = this.cells[j][i].value;
                            if(false===options.search(v) && ''!=v){
                                options.push(v);
								h[k++] = '<option value="'+v+'">'+v+'</option>';
                            }
                        }
						
                        h[k++] = '</select>';
                    }
					else h[k++] = labels[i].name;
                }
				else h[k++] = '&nbsp;';
				
                h[k++] = '</td>';
            }
            h[k++] = '</tr></table></div><br><div></div>';
            t.innerHTML = h.join("");
			this.Header = t.firstChild.firstChild;
        },
		
        getValueList:function(collIndex){
            var list = [],v;
            for(var i=0;i<this.cells.length;i++){
                if(!list.toString().match(this.cells[i][collIndex].value)){
                    v = this.cells[i][collIndex].value;
                    list.push('<option value="' + v +'">' + v + '</option>');
                }
            }
            return list.join('');
        },
        cleanUp:function(tt){
            // избегаем утечку памяти в Microsoft Internet Explorer
            for(var i=0;i<tt.cells.length;i++){
                for(var j=0;j<tt.cells[0].length;j++){
                    tt.cells[i][j].parent=null;
                    if(tt.cells[i][j].AutoCompleter){
                        tt.cells[i][j].AutoCompleter = null;
                    }
                }
            }
            var inp = document.getElementsByTagName('INPUT');
            for(var l=0;l<inp.length;l++){
                inp[l].onclick = inp[l].onkeydown = null;
            }
        }
    };
}



Вызов addHeaders в html должен идти ПЕРЕД show()!!!

ZoNT 02.09.2008 12:59

Цитата:

Сообщение от gagagogo (Сообщение 5236)
ZoNT, спасибо за советы. Как думаешь если оптимизировать можно в 2 секунды уложиться ? Или может лучше сгенерировать таблицу на php, а к ней уже обработчики событий прикрутить? Или может лучше вообще отказаться от этой затеи и написать на java аплет? Если у тебя есть можеш свой вариант скинуть ?

Свой вариант скинуть не могу (так как он делался для коммерческих целей), но твой мы можем доработать до этих самых двух секунд...

Если на пхп таблица сгенерится быстрее, то это конечно лучший вариант...

gagagogo 02.09.2008 13:32

Ага, учтя твои замечания думаю сделать так:
1 таблицу генерировать на пхп
2 сделать один input который будет бегать по ячейкам таблицы и менять значения в них.
3 на input повесить все события, и убрать объект cell - поидеи он тогда вообще не нужен будет

ZoNT 02.09.2008 13:35

смотри:
/*
SpreadSheet.js
*/
Array.prototype.search = function(search){
	for(var i=0,l=this.length;i<l;i++)if(this[i]==search)return i;
	return false;
}
 
/*
ЯЧЕЙКА ТАБЛИЦИ
*/
function cell(){
    this.r = 0;
    this.c = 0;
    this.parent = null;
    this.value = '';
    this.borderColor = '#7F9DB9';
    this.borderWidth = '1';
    this.defaultStyle = function(){
        this.borderColor = '#7F9DB9';
        this.borderWidth = '1';
    }
    this.activeStyle = function(){
        this.borderColor = '#000000';
        this.borderWidth = '3';
    }
    this.setAutoCompleter = function(url){}
    this.findTableCell = function(r,c){
        var t = this.parent._obj.getElementsByTagName('TABLE');
        return t[t.length-1].getElementsByTagName('TR')[this.r-1].getElementsByTagName('TD')[this.c-1];
    }
}
/*
ТАБЛИЦА
*/
function sheet(obj){
    return {
        row:1,
        col:1,
        cells:[], // хеш массив ячеек
        _obj:obj,
        cell:function(r,c){
            var rCount=0,cCount=0;
            while(this.cells.length < r){
                this.cells.push([]);
                rCount = this.cells.length - 1;
                while(this.cells[rCount].length < c){
                    this.cells[rCount].push(new cell());
                    cCount = this.cells[rCount].length - 1;
                    this.cells[rCount][cCount].r = rCount+1;
                    this.cells[rCount][cCount].c = cCount+1;
                    this.cells[rCount][cCount].parent = this;
                }
            }
            return this.cells[r-1][c-1];
        },
        moveTo:function(r,c){
			var t = this;
            if(r<1 || c<1 || r>t.cells.length || c>t.cells[0].length) return;

			t.cell(t.row,t.col).defaultStyle();
			t.updateCell(t.row,t.col);
			t.cell(r,c).activeStyle();
			t.updateCell(r,c);
			t.row=r;
			t.col=c;
        },
        updateCell:function(r,c){
            var input = this.Table.rows[r-1].cells[c-1].firstChild;
			var C = this.cell(r,c);
            input.style.borderWidth = C.borderWidth;
            input.style.borderColor = C.borderColor;
            if(''!=input.value && input.value!=C.value)
				C.value = input.value;
            input.value = C.value;
            input.focus();
        },
        show:function(){
            var t=[],i=0,currenCell;
            t[i++] = '<table cellspacing=0 cellpadding=0 class="Table">';
            var rCount = this.cells.length;
            var cCount = this.cells[0].length;
            var tt = this;
            var OnKeyDown = function(e){
				e=e||event;
                switch(e.keyCode||e.charCode){
                    case 37: tt.moveTo(tt.row,tt.col-1); break;  // move left
                    case 38: tt.moveTo(tt.row-1,tt.col); break;  // move up
                    case 39: tt.moveTo(tt.row,tt.col+1); break;  // move right
                    case 40: tt.moveTo(tt.row+1,tt.col); break;  // move down
                }
            }
 
			t[i++] = '<tr>';
			var h = this.Header.rows[0];
			for(var c=0; c<cCount; c++){
				currenCell = this.cells[0][c];
				t[i++] = '<td style="width:'+h.cells[c].offsetWidth+'px;"></td>';
			}
			t[i++] = '</tr>';
			
            for(var r=1; r<rCount; r++){
                t[i++] = '<tr>';
                for(var c=0; c<cCount; c++){
                    currenCell = this.cells[r][c];
                    t[i++] = '<td></td>';
                }
                t[i++] = '</tr>';
            }
            t[i++] = '</table>';
            this._obj.lastChild.innerHTML = t.join("");
			
			this.Table = this._obj.lastChild.firstChild;
			this.Table.style.width = this.Header.offsetWidth;
			
            window.onunload = function(){tt.cleanUp(tt)};
        },
        addHeaders:function(labelsList){ // labelList format: {name1:isSortable,name2:isSortable}
            var labels = [],h = [],k=0;
            for(var key in labelsList)
				labels.push({name:key,isSortable:labelsList[key]});
				
            var rCount = this.cells[0].length;
			var cCount = this.cells.length;
 
            var t = this._obj;
			
            h[k++] = '<div><table cellspacing="0" cellpadding="0"><tr>';
			
            for(var i=0;i<rCount;i++){
                h[k++] = '<td>';
                if(i<labels.length){
                    if(labels[i].isSortable){
						h[k++] = '<select style="background:#99CCFF;"><option>'+labels[i].name+'</option>';
						
						var options=[];
                        for(var j=0;j<cCount;j++){
							var v = this.cells[j][i].value;
                            if(false===options.search(v) && ''!=v){
                                options.push(v);
								h[k++] = '<option value="'+v+'">'+v+'</option>';
                            }
                        }
						
                        h[k++] = '</select>';
                    }
					else h[k++] = labels[i].name;
                }
				else h[k++] = '&nbsp;';
				
                h[k++] = '</td>';
            }
            h[k++] = '</tr></table></div><br><div></div>';
            t.innerHTML = h.join("");
			this.Header = t.firstChild.firstChild;
        },
		
        getValueList:function(collIndex){
            var list = [],v;
            for(var i=0;i<this.cells.length;i++){
                if(!list.toString().match(this.cells[i][collIndex].value)){
                    v = this.cells[i][collIndex].value;
                    list.push('<option value="' + v +'">' + v + '</option>');
                }
            }
            return list.join('');
        },
        cleanUp:function(tt){
            // избегаем утечку памяти в Microsoft Internet Explorer
            for(var i=0;i<tt.cells.length;i++){
                for(var j=0;j<tt.cells[0].length;j++){
                    tt.cells[i][j].parent=null;
                    if(tt.cells[i][j].AutoCompleter){
                        tt.cells[i][j].AutoCompleter = null;
                    }
                }
            }
            var inp = document.getElementsByTagName('INPUT');
            for(var l=0;l<inp.length;l++){
                inp[l].onclick = inp[l].onkeydown = null;
            }
        }
    };
}


<html>
    <head>
	<style>
	.Table {
		border-collapse:collapse;
	}
	.Table td {
		border:1px solid #7F9DB9;
		height:18px;
	}
	</style>
    </head>
    <body>
        <script type="text/javascript" src="sheet.js"></script>
        <div id="SpreadSheet" align="center"></div>
        <script>
            var b = new Date();
            var s = new sheet(document.getElementById('SpreadSheet'));
            s.cell(800,14);
            s.addHeaders({'Адрес установки':1,'Дом':1,'Под':1,'Switch':1,'IP адрес':1,'serial sw':1,'модуль':1,'1 модуль':1,'2 модуль':1,'Заказан':1,'Подготовлен':1,'Выдан':1,'Установлен':1,'Пометки':1});
			s.show();
            alert(((new Date()) - b)/1000);
        </script>
    </body>
</html>


Осталось только:
1) повесить обработку событий на саму таблицу (то есть обработчик будет всего один)
2) Завести один инпут (он будет редактировать значение текущей ячейки)

gagagogo 02.09.2008 17:13

Переписал генерацию таблицы и шапки на php, щас буду писать обработчики событий для перемещающегося INPUT. Что посоветуеш сделать ? removeChild INPUT из старой ячейки и appendChild INPUT в новую ? Или может сделать position:absolute и перемещать координаты INPUT? Мне вообщето больше второй вариант нравится.
<html>
<head>
<style>
	.SpreadSheet{border-collapse:collapse;}
	.SpreadSheet td {border:1px solid #7F9DB9;height:18px;}
	.SpreadSheet select{background:#99CCFF;}
</style>
</head>
<body>
<table class="SpreadSheet" id="3482624id"><th><select name="street"><option value="Адрес установки">Адрес установки</option><option value="Лесная">Лесная</option></select></th><th><select name="home"><option value="Дом">Дом</option><option value="25">25</option><option value="26">26</option></select></th><th><select name="porch"><option value="Под">Под</option><option value="1 подвал">1 подвал</option><option value="3 подвал">3 подвал</option></select></th><th><select name="dev_desc"><option value="Switch">Switch</option><option value="DES-3526">DES-3526</option></select></th><th><select name="IP"><option value="IP адрес">IP адрес</option><option value="10.100.40.28">10.100.40.28</option><option value="10.100.40.29">10.100.40.29</option></select></th><th><select name="serial_sw"><option value="serial sw">serial sw</option><option value="00-1C-F0-0F-9A-63">00-1C-F0-0F-9A-63</option><option value="00-1C-F0-0F-9A-9F">00-1C-F0-0F-9A-9F</option></select></th><th><select name="module0"><option value="модуль">модуль</option><option value="DEM-310GT V.D1">DEM-310GT V.D1</option></select></th><th><select name="module1"><option value="1 модуль">1 модуль</option><option value="E60N176001096">E60N176001096</option><option value="E60N176001091">E60N176001091</option></select></th><th><select name="module2"><option value="2 модуль">2 модуль</option><option value="E60N176001099">E60N176001099</option><option value="E60N176002084">E60N176002084</option></select></th><th><select name="orderDate"><option value="Заказан">Заказан</option><option value="39595">39595</option></select></th><th><select name="readyDate"><option value="Подготовлен">Подготовлен</option><option value="39597">39597</option></select></th><th><select name="givenDate"><option value="Выдан">Выдан</option><option value="39601">39601</option></select></th><th><select name="mountedDate"><option value="Установлен">Установлен</option><option value="39606">39606</option></select></th><tr><td>Лесная</td><td>25</td><td>1 подвал</td><td>DES-3526</td><td>10.100.40.28</td><td>00-1C-F0-0F-9A-63</td><td>DEM-310GT V.D1</td><td>E60N176001096</td><td>E60N176001099</td><td>39595</td><td>39597</td><td>39601</td><td>39606</td></tr><tr><td>Лесная</td><td>26</td><td>3 подвал</td><td>DES-3526</td><td>10.100.40.29</td><td>00-1C-F0-0F-9A-9F</td><td>DEM-310GT V.D1</td><td>E60N176001091</td><td>E60N176002084</td><td>39595</td><td>39597</td><td>39601</td><td>39606</td></tr></table>	<script>
		function sheet(objTable){
			var _sheet =  {
				cell:document.createElement('INPUT'),
				moveTo:function(row,coll){},
				init:function(){
					// ОБРАБОТЧИКИ СОБЫТИЙ ДЛЯ INPUT
				}
			};
			_sheet.init();
			return _sheet;
		}
		s = new sheet(document.getElementById('3482624id'));
	</script></body>
</html>

ZoNT 02.09.2008 17:33

Я думаю, что изменение таблицы будет вызывать нехилую перерисовку, так что надо минимизировать кол-во перерисовок таблицы. Соответственно, лучше в данном случае выглядит вариант с абсолютно спозиционированным инпутом, который находится ("летает") выше таблицы...

gagagogo 03.09.2008 12:26

Я тут переписал свой код. Когда курсор на нижней строке и мы нажимаем вниз - добавляется новая строка. Но в опере текст который я туда записываю не отображается в таблице. В IE & FF, работает как надо. Как с этим бороться ?
<html>
<head>
<style>
	.SpreadSheet{border-collapse:collapse;}
	.SpreadSheet td {border:1px solid #7F9DB9;height:18px;}
	.SpreadSheet select{background:#99CCFF;}
	.SpreadSheetActivCell{border:3px #000000 solid;}
</style>
</head>
<body>
<table class="SpreadSheet" id="9394688id"><th><select name="street"><option value="Адрес установки">Адрес установки</option><option value="Землянского">Землянского</option><option value="Удмуртская">Удмуртская</option></select></th><th><select name="home"><option value="Дом">Дом</option><option value="9">9</option><option value="29">29</option></select></th><th><select name="porch"><option value="Под">Под</option><option value="2">2</option><option value="1">1</option></select></th><th><select name="dev_desc"><option value="Switch">Switch</option><option value="DES-3526">DES-3526</option></select></th><th><select name="IP"><option value="IP адрес">IP адрес</option><option value="10.102.32.13">10.102.32.13</option><option value="10.108.12.233">10.108.12.233</option></select></th><th><select name="serial_sw"><option value="serial sw">serial sw</option><option value="PL0A175001634">PL0A175001634</option><option value="PL0A175001635">PL0A175001635</option></select></th><th><select name="module0"><option value="модуль">модуль</option><option value="DEM-310GT V.D1">DEM-310GT V.D1</option></select></th><th><select name="module1"><option value="1 модуль">1 модуль</option><option value="E60N164003935">E60N164003935</option><option value="E60N166003929">E60N166003929</option></select></th><th><select name="module2"><option value="2 модуль">2 модуль</option><option value="E60N164004518">E60N164004518</option><option value="E60N164005657">E60N164005657</option></select></th><th><select name="orderDate"><option value="Заказан">Заказан</option><option value="39358">39358</option></select></th><th><select name="readyDate"><option value="Подготовлен">Подготовлен</option><option value="39358">39358</option></select></th><th><select name="givenDate"><option value="Выдан">Выдан</option><option value="39360">39360</option></select></th><th><select name="mountedDate"><option value="Установлен">Установлен</option><option value="39384">39384</option></select></th><tr><td>Землянского</td><td>9</td><td>2</td><td>DES-3526</td><td>10.102.32.13</td><td>PL0A175001634</td><td>DEM-310GT V.D1</td><td>E60N164003935</td><td>E60N164004518</td><td>39358</td><td>39358</td><td>39360</td><td>39384</td></tr><tr><td>Удмуртская</td><td>29</td><td>1</td><td>DES-3526</td><td>10.108.12.233</td><td>PL0A175001635</td><td>DEM-310GT V.D1</td><td>E60N166003929</td><td>E60N164005657</td><td>39358</td><td>39358</td><td>39360</td><td>&nbsp;</td></tr></table>	<script>
		function sheet(objTable){
			var _sheet =  {
				rowIndex:null,
				collIndex:null,
				cell:document.createElement('INPUT'),
				_objTable:objTable,
				moveTo:function(row,coll){
					try{
					this.save();
					var rowMax  = this._objTable.rows.length-1; 		// число рядов
					var collMax = this._objTable.rows[1].cells.length; 	// число колонок
					//if(undefined==row || undefined==coll) return false;
					if(coll>collMax)coll=collMax;						// проверяем чтобы не вылететь за граници таблицы
					if(row>rowMax)row=rowMax;							// проверяем чтобы не вылететь за граници таблицы
					if(row<1)row=1										// проверяем чтобы не вылететь за граници таблицы
					if(coll<1)coll=1									// проверяем чтобы не вылететь за граници таблицы
					this.rowIndex  = row;
					this.collIndex = coll;
					coll--;
					cell = this._objTable.rows[row].cells[coll];
					var position = pos(cell);
					this.cell.style.top		=position[0];
					this.cell.style.left	=position[1];
					this.cell.style.width	=cell.clientWidth;
					this.cell.style.height	=cell.clientHeight;
					this.cell.value 		=cell.firstChild.nodeValue;/**/
					}catch(e){
						alert(e);
						return false;
					}
					return true;
				},
				save:function(){
					if(null==this.rowIndex || null==this.collIndex ||
					   undefined==this.rowIndex || undefined==this.collIndex
					   )
						return;
					var cell = this._objTable.rows[this.rowIndex].cells[this.collIndex-1];
					if(this.cell.value!=cell.firstChild.nodeValue){
						cell.firstChild.nodeValue = this.cell.value;
					}
				},
				addRow:function(){
					maxColl = this._objTable.rows[1].cells.length+1;
					var td,tr = document.createElement('TR');
					tbody = this._objTable.rows[1].parentNode;
					tbody.appendChild(tr);
					for(i=0;i<maxColl;i++){
						td = document.createElement('TD');
						tr.appendChild(td);
						td.appendChild(document.createTextNode(''));
					}
					//this.moveTo(this.rowIndex+1,this.collIndex);
					//this.cell.focus();
					tr=td=maxColl=null;
				},
				init:function(){
					// ОБРАБОТЧИКИ СОБЫТИЙ ДЛЯ INPUT
					this.cell.style.position='absolute';
					document.body.appendChild(this.cell);
					this.cell.className='SpreadSheetActivCell';
					this.cell.autocompliter='off';
					var tt = this;
					
					this.cell.onkeydown = function(e){
						lastCellIndex = tt._objTable.rows.length-1;
						e=e||event;
						switch(e.keyCode||e.charCode){
							case 37: tt.moveTo(tt.rowIndex,tt.collIndex-1); break;  // move left
							case 38: tt.moveTo(tt.rowIndex-1,tt.collIndex); break;  // move up
							case 39: tt.moveTo(tt.rowIndex,tt.collIndex+1); break;  // move right
							case 40: if(tt.rowIndex+1>lastCellIndex){tt.addRow();}tt.moveTo(tt.rowIndex+1,tt.collIndex); break;  // move down
						}
					}
					objTable.onclick = function(e){
						e=e||event;
						sorce = e.srcElement || e.target;
						var row = sorce.parentNode.rowIndex
						var coll= sorce.cellIndex+1;
						if(!tt.moveTo(row,coll))return;
						tt.cell.focus();
					};
					this.moveTo(1,1);
					this.cell.focus();
				}
			};
			_sheet.init();
			return _sheet;
		}
		s = new sheet(document.getElementById('9394688id'));

		
		function pos(obj){
			var x=0,y=0;
			do{
				x += obj.offsetTop;
				y += obj.offsetLeft;
			}while(obj=obj.offsetParent)
			return [x,y];
		}

		
	</script></body>
</html>

ZoNT 03.09.2008 12:43

У меня в опере всё ОК

gagagogo 05.09.2008 11:13

Наверное глупый вопрос, но всёже.... Как можно передать большой кусок html в функцию на JavaScript. В строку просто так не запихнёш - надо экранировать кавычки пробелы удалять. Я ничё лучше не придумал:
<div style="display:none" id="content123">сюда я помещаю весь текст<br><hr> и тд.</div>
<script>
  function foo(content){
       alert(content);
   }
   foo(document.getElementsById('content123').innerHTML);
</script>

ZoNT 05.09.2008 11:16

и чем тебе это не нравится?

gagagogo 05.09.2008 11:20

коряво как то)

ZoNT 05.09.2008 11:44

сам ты корявый...

Kolyaj 06.09.2008 19:57

Цитата:

Сообщение от ZoNT
и чем тебе это не нравится?

Ну, например, если в коде будет <img src="1.gif" />, то в скрипт придет <img src="1"> (как минимум в FF). Уж лучше тогда в textarea пихать. А лучше все-таки экранировать все нужное.

ZoNT 06.09.2008 22:58

<html>
<body>
<div style="display:none" id="content123">сюда я помещаю весь текст<br><hr><img src="1.gif" /> и тд.</div>
<script>
  function foo(content){
       alert(content);
   }
   foo(document.getElementById('content123').innerHTML);
</script>
</body>
</html>


Никаких "<img src="1"> (как минимум в FF)" нет.

Kolyaj 06.09.2008 23:48

ZoNT, не поверишь, но у меня закрывающие слэши убираются (FF2) :)
Т.к. браузер оперирует все-таки html-ом, а не xml-ом.
В ИЕ, кстати, местами будут пропадать-появляться кавычки у аттрибутов.

ZoNT 08.09.2008 09:52

и тебя это чем-то волнует???

Kolyaj 08.09.2008 10:36

Меня это ни капельки не волнует, я не собираюсь передавать строки в js таким извратным способом. Я лишь говорю, что в js зачастую будет приходить не та строка, которая ушла из php.

ZoNT 08.09.2008 11:10

ну если надо из пхп передавать именно строку, то надо сразу делать \/, \\ и т.д.

gagagogo 17.09.2008 18:05

Надо предать много данных обратно на сервер. Загружаю таблицу с сервера (у меня в ней 14 полей). Пользователь в ней что то меняет или добавляет, а потом изменения нужно сохранить обратно на сервере. Как лучше передать измененные данные? Ведь если пользователь добавил 10 новых строк это уже 140 ячеек. Если отправлять эти данные постом через аякс можно ли как то проверить пришли ли они без ошибок? Или может какой то другой способ сдесь более применим ?

Андрей Параничев 17.09.2008 18:12

gagagogo,
Мне кажется лучше обходить на клиенте измененные ячейки и составлять JSON объект, который уже будет отправлен на сервер. Все-таки обмениваться html данными - не красиво.

gagagogo 17.09.2008 22:07

Нет, конечно я не буду пересылать ячейки наблици. Но делать JSON тоже не хочу потому что насервере нет расширени я для JSON, а парсить его в ручную чёт неохота. Думаю сфорганить строку с разделителями из выдранных из таблички данных. Не знаю как лучше сделать отправлять данные через аякс или форму?


Часовой пояс GMT +3, время: 12:18.