Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   Сделать историю? (https://javascript.ru/forum/misc/52788-sdelat-istoriyu.html)

makar3000 07.01.2015 01:30

Сделать историю?
 
Доброй ночи! Мои мозги закипают уже :help:

Имеется набор функций моего редактора, перед выполнением каждой фукции я сохраняю прошлый результат всего редактора в массив. Есть кнопка "Вернуть" при нажатии возвращается преведущий результат...

Дело в том что такой способ полностью работает, но так как я в массив заношу каждый раз огромный код сжатый код, хотелось бы ограничить "Возвращение" до 10 этапов

Как реализовано у меня:

Заход1:
Меняем данные в редакторе и пытаемся вернутся back(); => удивительно но работает сколько бы раз не возвращались (до 10)
Заход2:
Пытаемся после возвращений что-то изменить данные редактора и пытаемся вернутся back(); => не хочет возвращаться вообще

h_i = 1; // указал единицу так как в массиве первый ключ 1
history = [];

addhistory(); // Запускаю первый раз что бы добавить данные "как есть"

function addhistory() {
   content = '';//тут я загоняю сгенерированный код редактором в JSON
  
   if( history.length > 11 ) { // на 10 раз
     h_i = 1;
     history = [];
   }


   history.unshift(content);


}

function back() {
  if( history.length > h_i ) { //смотрим что-бы хватало истории 
     readcontent( history[ h_i ] ); // возвращаем предыдущие данные
     h_i++;
  }
}

bes 07.01.2015 11:28

Цитата:

Сообщение от makar3000
 if( history.length > 11 ) { // на 10 раз
     h_i = 1;
     history = [];
   }

то есть ты каждый раз обнуляешь после 11 сохранений
копируй или смещай элементы массива вперед, в конец добавляй последний результат сохранения

makar3000 07.01.2015 14:37

Делал вместо очистки .pop() все работало! Но если по второму кругу нажимать back() то в массиве были данные из первого круга и возвращалось то что было в первом круге а не во втором

bes 07.01.2015 15:22

Цитата:

Сообщение от makar3000
Делал вместо очистки .pop() все работало! Но если по второму кругу нажимать back() то в массиве были данные из первого круга и возвращалось то что было в первом круге а не во втором

<input>
<button>save</button>
<script>
document.querySelector("button").addEventListener("click", function () {
	if (!this.mas) this.mas = [];
	if (this.mas.length > 9) this.mas.shift();
	this.mas.push(this.previousElementSibling.value);
	console.log(this.mas);
});
</script>

bes 07.01.2015 17:15

опиши логику переходов по истории

<input>
<button class="save">save</button>
<button class="back">back</button>
<button class="forward">forward</button>

<script>
function addElement(element, mas, limit) {
	if (mas.length > limit - 1) mas.shift();
	mas.push(element);
}

document.querySelector(".save").addEventListener("click", function () {
	var backBut = document.querySelector(".back");
	delete backBut.n;
	if (!this.mas) this.mas = [];
	var input = document.querySelector("input");
	addElement(input.value, this.mas, 10);
	input.select();
	console.log(this.mas);
});
document.querySelector(".back").addEventListener("click", function () {
	var saveBut = document.querySelector(".save");
	if (!saveBut.mas) saveBut.mas = [];
	mas = saveBut.mas;
	if (this.n == undefined) {
		(!mas.length) ? this.n = 0 : this.n = mas.length - 1;
	}
	(this.n <= 0) ? this.n = 0 : this.n--;
	document.querySelector("input").value = mas[this.n]; 
	console.log("n=" + this.n + "; mas[n]=" + mas[this.n]);
});
</script>

Яростный Меч 07.01.2015 17:51

Цитата:

Сообщение от bes
опиши логику переходов по истории

Обычно логика такая (если по уму делать):

есть массив (очередь), и есть указатель на текущий пункт в нем. Всё что перед указателем - "область повторов", прочее - "область отмен" (обе области могут быть пустые).

Функция undo - если есть команды в "области отмен", отменяем команду, на которой стоит указатель, перемещаем оный на шаг назад.

Функция redo - если есть команды в "области повторов", перемещаем указатель на шаг вперед и выполняем команду под ним.

Функция action (юзер хочет что-то сделать) - удаляем всё из "области повторов", формируем команду, ставим перед указателем, делаем redo. Если в очереди стало больше 10 элементов, удаляем самый старый.


Каждый элемент в очереди - команда, которую можно выполнить или отменить.

bes 07.01.2015 18:46

Цитата:

Сообщение от Яростный Меч
Обычно логика такая (если по уму делать):

есть массив (очередь), и есть указатель на текущий пункт в нем. Всё что перед указателем - "область повторов", прочее - "область отмен" (обе области могут быть пустые).

Функция undo - если есть команды в "области отмен", отменяем команду, на которой стоит указатель, перемещаем оный на шаг назад.

Функция redo - если есть команды в "области повторов", перемещаем указатель на шаг вперед и выполняем команду под ним.

Функция action (юзер хочет что-то сделать) - удаляем всё из "области повторов", формируем команду, ставим перед указателем, делаем redo. Если в очереди стало больше 10 элементов, удаляем самый старый.


Каждый элемент в очереди - команда, которую можно выполнить или отменить.

отобрази на мой пример с тремя кнопками
save - action - удаляем все предыдущие элементы массива перед текущим, добавляем элемент в конец массива
back - undo - переходим на предыдущий элемент массива, если он есть
forward - redo - переходим на последующий элемент массива, если он есть
так?

makar3000 07.01.2015 21:13

Цитата:

Сообщение от Яростный Меч (Сообщение 350137)
Обычно логика такая (если по уму делать):

есть массив (очередь), и есть указатель на текущий пункт в нем. Всё что перед указателем - "область повторов", прочее - "область отмен" (обе области могут быть пустые).

Функция undo - если есть команды в "области отмен", отменяем команду, на которой стоит указатель, перемещаем оный на шаг назад.

Функция redo - если есть команды в "области повторов", перемещаем указатель на шаг вперед и выполняем команду под ним.

Функция action (юзер хочет что-то сделать) - удаляем всё из "области повторов", формируем команду, ставим перед указателем, делаем redo. Если в очереди стало больше 10 элементов, удаляем самый старый.


Каждый элемент в очереди - команда, которую можно выполнить или отменить.

Что-то я не понял, так что-ли?:

action и redo у меня не зависимы, action происходит в редакторе, а redo конкретно по кнопке исполняется

var history = [];
var ukazatel;

function redo() {
  if( ! history[ ukazatel + 1 ] ) {
         return false; //Нет в области повторов
    }
     ukazatel++;
    command = history[ ukazatel ]; 
   //Выполняем
}

function undo() {
    if( ! history[ ukazatel - 1 ] ) {
         return false; //Нет в области отмен
    }

    command = history[ ukazatel ]; 
   //Отмена
    ukazatel--;
} 

function action() {
  if( ukazatel == undefined ) 
     ukazatel = 1;
  else
     ukazatel++;

  history[ ukazatel-1 ] = COMMAND; // Добавляем команду
  
  if( history.length > 10 ) {
     history.pop(); // Удаляем последний элемент
  }
}

Яростный Меч 07.01.2015 21:38

Вот набросок очереди команд:
function CommandQueue(limit) {
  this._limit = limit || 10;
  this._arr = [];
  this._pointer = -1;
}

CommandQueue.prototype.undoCount = function() {
  return this._pointer + 1;
};
CommandQueue.prototype.redoCount = function() {
  return this._arr.length - this._pointer - 1;
};

CommandQueue.prototype.undo = function() {
  if (!this.undoCount()) {
    return false;
  }
  this._arr[this._pointer].undo();
  this._pointer--;
  return true;
};

CommandQueue.prototype.redo = function() {
  if (!this.redoCount()) {
    return false;
  }
  this._pointer++;
  this._arr[this._pointer].redo();
  return true;
};

CommandQueue.prototype.action = function(command) {
  this._arr.splice(this._pointer + 1, this.redoCount(), command);
  this.redo();
  if (this._arr.length > this._limit) {
    this._arr.shift();
    this._pointer--;
  }
};


использование:
var q = new CommandQueue(10);
q.action({
  undo: function() {...},
  redo: function() {...}
});

makar3000 07.01.2015 23:22

Спасибо, вы очень помогли. Разобрался. Вопрос решен


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