How to write a cyclic generator which randomly picks items from a message array but does not repeat a single item until every item was displayed once?

I need a message generator that generates a Quote included in array. But I have to :

  1. Make sure that each randomly displayed message is displayed only 1x until all messages have been displayed / there are no duplicates until all have been displayed.

  2. When all messages have been displayed, allow all messages again and repeat 2.

This is what I have come up so far:

let btn = document.getElementById('btn');
let output = document.getElementById('output');

let quotes = [
  'No one is perfect - that’s why pencils have erasers. - Wolfgang Riebe',
  'Have no fear of perfection - you will never reach it. - Salvador Dali',
  'The tallest mountain started as a stone. - One Punch Man Intro',
  'Make it work. Make it nice. Make it fast. Always obey this order! - kiraa',
  'A good programmer is someone who always looks both ways before crossing a one-way street. – Doug Linder',
  'If debugging is the process of removing software bugs, then programming must be the process of putting them in. - Edsger W. Dijkstra',
];

btn.addEventListener('click', function() {
  let randomQuote = quotes[Math.floor(Math.random() * quotes.length)]
  output.innerHTML = randomQuote;
})
#container {
  background-color: mediumpurple;
  border: 5px solid white;
  height: 300px;
  width: 700px;
  margin: 0 auto;
  text-align: center;
  border-radius: 25px;
}
#btn {
  margin:  50px auto;
  height: 50px;
  width: 250px;
  font-size: 20px;
  background-color: white;
  font-family: Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;
  border-radius: 30px;
}

output {
  margin: 25px auto;
  font-size: 20px;
  color: white
}
<div id="container">
  <button id="btn">Get your message of the day</button>

  <div id="output"> Press it :)</div>
</div>

Answer

A possible approach was to create a click handler which can access the bound original array and also does mutate a bound (always self sacrificing) copy of the former.

In case sacrifice … the array which one is going to deplete/mutate by constantly/repeatedly slicing a random quote/string from it … is not provided or is empty, one does assign a new shallow copy of the original array to the handlers this-context. Thus the handler starts operating again a renewed/complete set of quote items …

function depleteAndDisplayBoundQuotesRandomlyAndRepeat () {
  let { output, original, sacrifice } = this;
  if (
    !Array.isArray(sacrifice) ||
    (sacrifice.length === 0)
  ) {
    sacrifice = this.sacrifice = Array.from(original);
  }
  // console.log(sacrifice);

  const idx =
    Math.floor(Math.random() * sacrifice.length);

  // mutate/deplete the sacrifice quotes array.
  const quote = sacrifice.splice(idx, 1);

  output.textContent = quote;
}

const quotes = [
  'No one is perfect - that’s why pencils have erasers. - Wolfgang Riebe',
  'Have no fear of perfection - you will never reach it. - Salvador Dali',
  'The tallest mountain started as a stone. - One Punch Man Intro',
  'Make it work. Make it nice. Make it fast. Always obey this order! - kiraa',
  'A good programmer is someone who always looks both ways before crossing a one-way street. – Doug Linder',
  'If debugging is the process of removing software bugs, then programming must be the process of putting them in. - Edsger W. Dijkstra',
];

document
  .querySelector('#btn')
  .addEventListener('click',
    depleteAndDisplayBoundQuotesRandomlyAndRepeat.bind({
      output: document.querySelector('#output'),
      original: quotes,
    })
  );
#container {
  background-color: mediumpurple;
  border: 5px solid white;
  height: 300px;
  width: 700px;
  margin: 0 auto;
  text-align: center;
  border-radius: 25px;
}
#btn {
  margin:  50px auto;
  height: 50px;
  width: 250px;
  font-size: 20px;
  background-color: white;
  font-family: Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;
  border-radius: 30px;
}

output {
  margin: 25px auto;
  font-size: 20px;
  color: white
}
<div id="container">
  <button id="btn">Get your message of the day</button>

  <div id="output"> Press it :)</div>
</div>