Search code examples
javascriptjquerygoogle-chromesafariopera

Why does my code not work in Safari or Opera?


There is a function in js which displays messages to the table (messages are stored in json). In Google Chrome, it works, but Safari, Opera or Microsoft Edge - no! There is a mistake in code which is associated with the call to setTimeout (callback, 5000)(nothing is sent to the callback).So, For (var i = 0; i <respond.length; i ++) will not work since respond === undefined.

But why is it so?

callback(
  [{
      "time": "1500303264",
      "user": "qwe",
      "message": "we",
      "id": 1
    },
    {
      "time": "1500303987",
      "user": "Max",
      "message": "q",
      "id": 2
    }
  ]);

function smile(mess) {
  var smile = ":)";
  var graficSmile = "<img src = './image/Smile.png' alt='Smile' align='middle'>";
  var string_with_replaced_smile = mess.replace(smile, graficSmile);

  var sad = ":("
  var graficSad = "<img src = './image/Sad.png' alt='Smile' align='middle'>";
  var string_with_replaced_smile_and_sad = string_with_replaced_smile.replace(sad, graficSad);

  return string_with_replaced_smile_and_sad;
}

$.getJSON('data/messages.json', callback);
var exists = [];

function callback(respond) {
  var timeNow = Date.now();

  for (var i = 0; i < respond.length; i++) {
    var data = respond[i];

    if (exists.indexOf(data.id) != -1) continue;

    var timeInMessage = data.time * 1000;
    var diff_time = (timeNow - timeInMessage);

    if (diff_time <= 3600000) {
      var rowClone = $('.mess_hide').clone().removeClass('mess_hide');

      var newDate = new Date(timeInMessage);
      var dateArray = [newDate.getHours(), newDate.getMinutes(), newDate.getSeconds()]
      var res = dateArray.map(function(x) {
        return x < 10 ? "0" + x : x;
      }).join(":");

      $('#messages').append(rowClone);
      $('.time', rowClone).html(res);
      $('.name', rowClone).html(data.user);
      $('.message', rowClone).html(smile(data.message));
      $('.scroller').scrollTop($('#messages').height());

      exists.push(data.id);
    }
  }
  setTimeout(function(){callback(respond)}, 5000);
}
.scroller {
  width: 490px;
  height: 255px;
  max-height: 255px;
  overflow-y: auto;
  overflow-x: hidden;
}

table#messages {
  min-height: 260px;
  width: 100%;
  background: #fffecd;
  border: none;
}

table#messages::-webkit-scrollbar {
  width: 1em;
}

table#messages::-webkit-scrollbar-track {
  -webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
}

table#messages::-webkit-scrollbar-thumb {
  background-color: darkgrey;
  outline: 1px solid slategrey;
}

tr {
  height: 20%;
  display: block;
}

td.time,
td.name {
  width: 70px;
  max-width: 75px;
  text-align: center;
}

td.name {
  font-weight: bold;
}

form#text_submit {
  display: inline-flex;
  align-items: flex-start;
}

input#text {
  width: 370px;
  height: 30px;
  margin-top: 20px;
  background: #fffecd;
  font-family: 'Montserrat';
  font-size: 16px;
  border: none;
  align-self: flex-start;
}

input#submit {
  padding: 0;
  margin-left: 21px;
  margin-top: 21px;
  height: 30px;
  width: 95px;
  background: #635960;
  border: none;
  color: white;
  font-family: 'Montserrat';
  font-size: 16px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="scroller">
  <table id="messages">
    <tr class="mess_hide">
      <td class="time"></td>
      <td class="name"></td>
      <td class="message"></td>
    </tr>
  </table>
</div>
<form method="POST" id="easyForm">
  <input type="text" name="text" id="text">
  <input type="submit" value="Send" id="submit">
</form>
</div>

Chrome Chrome

Opera Opera


Solution

    1. Since it is assumed that the var exists - array, but the value of the array ([]) is assigned to it only later, after the call $.getJSON(...). So, when callback is called for the first time value [] is not set for exists.We just need to move var exists above the first call of callback.
    2. When callback is called by the timer, nothing is passed to it. But timer needs to reread the messages from the file and display them on the screen.So, instead setTimeout(function(){callback(respond)}, 5000); we need setTimeout(function(){$.getJSON('data/messages.json', callback);}, 5000);.

    var exists = [];
    $.getJSON('data/messages.json', callback);
    
    function callback(respond) {
      var timeNow = Date.now();
    
      for (var i = 0; i < respond.length; i++) {
        var data = respond[i];
    
        if (exists.indexOf(data.id) != -1) continue;
    
        var timeInMessage = data.time * 1000;
        var diff_time = (timeNow - timeInMessage);
    
        if (diff_time <= 3600000) {
          var rowClone = $('.mess_hide').clone().removeClass('mess_hide');
    
          var newDate = new Date(timeInMessage);
          var dateArray = [newDate.getHours(), newDate.getMinutes(), newDate.getSeconds()]
          var res = dateArray.map(function(x) {
            return x < 10 ? "0" + x : x;
          }).join(":");
    
          $('#messages').append(rowClone);
          $('.time', rowClone).html(res);
          $('.name', rowClone).html(data.user);
          $('.message', rowClone).html(smile(data.message));
          $('.scroller').scrollTop($('#messages').height());
    
          exists.push(data.id);
        }
      }
      setTimeout(function() {
        $.getJSON('data/messages.json', callback);
      }, 5000);
    }