Расширение Chrome — ввод текста и события включения не реагируют на внешнее отображение

#javascript #css #google-chrome #google-chrome-extension

#javascript #css #google-chrome #google-chrome-расширение

Вопрос:

Я разрабатываю расширение Chrome для быстрого доступа к билетам JIRA. Таблица с текстовыми элементами «случайным образом» очень медленно реагирует на события ввода / страницы, такие как on hover , focus , и text input , иногда для ответа требуется по крайней мере НЕСКОЛЬКО секунд.

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

Это происходит ТОЛЬКО тогда, когда я использую внешний дисплей (MacBook Pro 13 дюймов, 2017, 8 ГБ через USB-C концентратор).

Я заметил: 1) Тот же код на более мощных машинах работает нормально, используя те же периферийные устройства 2) Все работает нормально, когда я перетаскиваю окно браузера на дисплей моего ноутбука 3) Это происходит, по-видимому, случайным образом в зависимости от позиции ввода во всплывающем окне. Изменение размера верхнего и нижнего полей часто может помочь либо решить проблему, либо переместить ее в другую строку.

Я создал функцию для изменения размера верхнего и нижнего полей в зависимости от количества элементов, но это только смягчает проблему, а не полностью ее решает.

FWIW, не похоже, что используется ужасный объем памяти, и система обнаруживает входные данные, поскольку она замечает ключевые события. Текстовые поля с проблемами не занимают больше места на процессоре / памяти, чем те, которые этого не делают.

popup.html

 <!DOCTYPE html>
<html lang="en" dir="ltr">
  <head>
    <link href="https://fonts.googleapis.com/css?family=IBM Plex Mono:400,400i|IBM Plex Sans Condensed:400,400i|IBM Plex Sans:100,100i,400,400i,700,700i|IBM Plex Serif:400,400i" rel="stylesheet">
    <link rel="stylesheet" href="popup-style.css">
    <style type="text/css"> </style>
    <meta charset="utf-8">
    <title>Quick Ticket For JIRA</title>
  </head>
  <body>
    <div class="NewJIRAForm">
      <div class="header">
        <h1>QUICK TICKET FOR JIRA</h1>
        <div class="QuickJIRAcontrols">
          <input type="button" id='optionsButton' value="Settings" class="controlButtons">
          <input type="button" id='toggleAddNewButton' value="Add New" class="controlButtons">
        </div>
      </div>
      <div class="addNewForm" id="addNewForm">
        <div class="addFirstRowForm">
          <input type="text" name="newJIRABoardName" placeholder="Name of your New JIRA board" class="newJIRABoardNameInputField"  id="newJIRABoardName">
          <input type="text" name="newJIRABoardKey" placeholder="Project Key" class="newJIRABoardKeyInputField" id="newJIRAProjectKey" >
        </div>
        <div class="addSecondRowForm">
          <input type="text" name="newJIRABaseURL" placeholder="Base URL of your JIRA board" class="newJIRABaseURLField" id='newJIRABaseURL'>
          <input type="button" id='addNewButton' value="Add">
        </div>
      </div>
    </div>
    <div id='CurrentQuickJIRAs' class="CurrentQuickJIRAs">
    </div>
  </body>
  <script src="popup.js"></script>
</html>
 

popup.js

 document.addEventListener('DOMContentLoaded', documentEvents  , false);


// using local array to avoice async issues;
var localQuickJiraArray = [];
var addNewQuickJIRAIsShown;

var currentNewJIRABoardNameTextInput;
var currentNewJIRABoardURLTextInput;
var currentNewJIRABoardProjectKeyTextInput;



function documentEvents() {

  document.getElementById('addNewButton').addEventListener('click',
    function() { addNewQuickJIRA(document.getElementById('newJIRABaseURL') , document.getElementById('newJIRABoardName'), document.getElementById('newJIRAProjectKey'));
  });

  document.getElementById('toggleAddNewButton').addEventListener('click',
    function() { toggleAddNewQuickJIRA();
  });

  document.getElementById('optionsButton').addEventListener('click',
    function() { chrome.tabs.create({'url': "/options.html" } );
  });

  document.getElementById("newJIRABoardName").addEventListener("keyup", saveNewFormData);
  document.getElementById("newJIRAProjectKey").addEventListener("keyup", saveNewFormData);
  document.getElementById("newJIRABaseURL").addEventListener("keyup", saveNewFormData);

  //sync local array of QuickJIRAs with Chrome Storage

  chrome.storage.sync.get(function(data) {
    if (Object.keys(data).length > 0 amp;amp; data.QuickJIRAs ) {
      localQuickJiraArray = data.QuickJIRAs;
    }
    chrome.storage.sync.set(data, function() {
      drawCurrentQuickJIRATable();
      // logStorage();
    });
  });
}

function saveNewFormData() {

  currentNewJIRABoardNameTextInput = document.getElementById("newJIRABoardName").value;
  currentNewJIRABoardURLTextInput = document.getElementById("newJIRABaseURL").value;
  currentNewJIRABoardProjectKeyTextInput = document.getElementById("newJIRAProjectKey").value;

  if ( currentNewJIRABoardNameTextInput == "" amp;amp; currentNewJIRABoardURLTextInput == "" amp;amp; currentNewJIRABoardProjectKeyTextInput == "" ) {
    isDataToPersist = false;
  } else {
    isDataToPersist = true;
  }

  chrome.runtime.sendMessage({
    currentNewJIRABoardNameTextInput: currentNewJIRABoardNameTextInput,
    currentNewJIRABoardURLTextInput: currentNewJIRABoardURLTextInput,
    currentNewJIRABoardProjectKeyTextInput: currentNewJIRABoardProjectKeyTextInput,
    isDataToPersist: isDataToPersist
  },
    function(response) {
      if (response == "saved") {
      } else {
        throw new Error("Error Persisting data while adding Quick Ticket");
      }

    }
  );
}

function drawCurrentQuickJIRATable() {

  chrome.storage.sync.get(function(data){
    // logStorage();
    if (Object.keys(data).length> 0 amp;amp; data.QuickJIRAs != undefined amp;amp; data.QuickJIRAs.length > 0) {

      // Clear current jiras
      document.getElementById('CurrentQuickJIRAs').innerHTML = '' ;

      //Draw New Table
      //**could improve by just adding the last one and not clearing
      for (var i = 0; i < data.QuickJIRAs.length; i  ) {
        var JIRABoardID = data.QuickJIRAs[i].JIRABoardName;
        var JIRABoardBaseURL = data.QuickJIRAs[i].JIRABaseURL;
        document.getElementById('CurrentQuickJIRAs').innerHTML  = '<div class="quickJIRARow">'  
        '<a class="goNewLink" href="'   data.QuickJIRAs[i].JIRABaseURL   "/"   data.QuickJIRAs[i].JIRAProjectKey   ' "> '   data.QuickJIRAs[i].JIRABoardName   '</a>'  
        '<input type="text" placeholder="Ticket Number" id="inputFieldBoardID_'   i   '" '   ' class="goToInput">'  
        '<div class="quickJIRARowButtons">'  
        '<button type="button" id="goNewButton_'   i   '" '   ' class="goNewButton">New Tab</button>'  
        '<button type="button" id="goCurrentButton_'   i   '" '   ' class="goCurrentButton">Current Tab</button>'  
        '<button type="button" id="removeButton_'   i   '" '   ' class="removeButton">Remove</button>'  
        '</div>'
        '</div>' ;
      }

      //add click function to link;
      var jiraBoardLinks = document.getElementsByTagName("a");
      for (var i = 0; i < jiraBoardLinks.length; i  ) {
          (function () {
              var link = jiraBoardLinks[i];
              var url = link.href;
              link.onclick = function () {
                  chrome.tabs.create({active: true, url: url});
              };
          })();
      }

      // Set Go New Button Click Event
      var goButtonArray = document.getElementsByClassName('goNewButton');
      for (var x = 0; x < goButtonArray.length; x  ) {
        var elementID = "goNewButton_"   String(x);
        document.getElementById(elementID).addEventListener('click', function () {
          var newTab = true;
          navigateToQuickJIRA(this, newTab);
        });
      }

      // Set Go Current Button Click Event
      var goButtonArray = document.getElementsByClassName('goCurrentButton');
      for (var x = 0; x < goButtonArray.length; x  ) {
        var elementID = "goCurrentButton_"   String(x);
        document.getElementById(elementID).addEventListener('click', function () {
          var newTab = false;
          navigateToQuickJIRA(this, newTab);
        });
      }

      // Set Go Remove Button Click Event
      var goButtonArray = document.getElementsByClassName('removeButton');
      for (var x = 0; x < goButtonArray.length; x  ) {
        var elementID = "removeButton_"   String(x);
        document.getElementById(elementID).addEventListener('click', function () {
          removeJIRA(this);
        });
      }

      // Set Go To JIRA in current Tab on Return and
      var goToInputArray = document.getElementsByClassName('goToInput');
      for (var x = 0; x < goToInputArray.length; x  ) {
        var elementID = "inputFieldBoardID_"   String(x);
        document.getElementById(elementID).addEventListener("keyup", function (event) {
          if (event.key === "Enter") {
            var newTab = false;
            navigateToQuickJIRA(this, newTab);
            this.value = "";
          }
        });
      }

      //To-Do: Add Options to Keep Add Window open
      toggleAddNewQuickJIRA(false);
    } else {
      document.getElementById('CurrentQuickJIRAs').innerHTML = '' ;
      toggleAddNewQuickJIRA(true);
    }
    checkIfExistingAddNewFields()
  });

}

function handleInputFromGoToInput(textfield) {

}

//Check to see if user is mid adding a new JIRA
function checkIfExistingAddNewFields() {
  // Send message to background to get current input values if user was mid input and closed the popup
  chrome.runtime.sendMessage({
    checkingForData : true
  },
    function(response) {
      if (response.currentNewJIRABoardNameTextInput != undefined amp;amp; response.currentNewJIRABoardURLTextInput != undefined amp;amp; response.currentNewJIRABoardProjectKeyTextInput != undefined) {
        document.getElementById("newJIRABoardName").value = response.currentNewJIRABoardNameTextInput;
        document.getElementById("newJIRABaseURL").value = response.currentNewJIRABoardURLTextInput;
        document.getElementById("newJIRAProjectKey").value = response.currentNewJIRABoardProjectKeyTextInput;
        toggleAddNewQuickJIRA(true);
      }
    }
  );
}


function navigateToQuickJIRA (button, newTab) {
  // Get the value of button Id to use to map to coresponding textfield
  var idValue = String(button.id).split("_").pop();
  var goToInputId = "inputFieldBoardID_"   idValue;

  var goToInputIdValue = document.getElementById(goToInputId).value;
  //Get base URL value from Storage
  // ** Change to local Array
  var projectKey = localQuickJiraArray[idValue].JIRAProjectKey;

  var goToInputIdValue= validateTicketNumberInput(goToInputIdValue, projectKey);

  chrome.storage.sync.get(function(data){
      if(chrome.runtime.lastError) {
          console.error(chrome.runtime.lastError);
      } else {
          console.log(data);
          var jiraBoardID = data.QuickJIRAs[idValue].JIRABaseURL;
          var jiraURL = jiraBoardID   "/"  goToInputIdValue;
          //Need function to avoid race-condition, could probably use callback in the future
          goToInputIdValue.value = "";
          gotoNewURL(jiraURL, newTab);
      }
  });
}

function validateTicketNumberInput(goToInputIdValue, projectKey){
  if (goToInputIdValue.length > projectKey.length) {
    var inputToCheckForProjectKey = goToInputIdValue.substr(0, projectKey.length 1);
  }

  //Check if input is just numbers - if yes, add the project key to the front and dash - it's valid
  //Check if input is contains valid project key in the right location with a dash - if yes - it's valid
  //else - not a valid input - throw error

  if (/^d $/.test(goToInputIdValue)) {
    var sanitizedInput = projectKey   "-"   goToInputIdValue;
    return sanitizedInput;
  } else if (inputToCheckForProjectKey !== 'undefined' amp;amp; inputToCheckForProjectKey == projectKey   "-") {
    return goToInputIdValue;
  } else {
    alert("It looks like your ticket number isn't valid for this Project. Please enter a valid ticket number.");
    throw new Error("Invald Ticket Number Entered");
  }
}

function gotoNewURL(jiraURL, newTab) {

  if (newTab == false) {
    chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
      var tab = tabs[0];
      chrome.tabs.update(tab.id, { url : jiraURL });
    });
  } else {
    chrome.tabs.create({ url : jiraURL });
  }

}

function removeJIRA(button) {

  var doesWantToDelete = confirm("Do you really want to Delete that link?");

  if (doesWantToDelete == true ) {
    var idValue = String(button.id).split("_").pop();

    //Get base URL value from Storage
    chrome.storage.sync.get(function(data){
        if(chrome.runtime.lastError) {
            console.error(chrome.runtime.lastError);
        } else {
            data.QuickJIRAs.splice(idValue, 1);
            localQuickJiraArray.splice(idValue, 1);
        }
        chrome.storage.sync.set(data, function() {
          //Race condition - use callback in the future
          drawCurrentQuickJIRATable();
        });
    });
  }

}

function addNewQuickJIRA(baseURLInput , boardNameInput, projectKeyInput) {

  if (baseURLInput.value == "" || boardNameInput.value == "" || projectKeyInput.value == "") {
    alert("Looks like some fields are missing. Please fill in all fields before adding a new Quick JIRA");
    throw new Error("missing fields upon Quick JIRA submission");
  }

  var baseURL = baseURLInput.value.replace(//$/, '');
  baseURL = validateBaseURL(baseURL);
  var boardName = validateBoardName(boardNameInput.value.trim());
  var projectKey = validateProjectKey(projectKeyInput.value.trim());
  var doesExist = checkIfInputDataDoesExist(baseURL, boardName, projectKey);

  if (doesExist == false) {
    chrome.storage.sync.get(function(data) {
      var objectToAdd = {'JIRABaseURL' : baseURL , 'JIRABoardName' : boardName , 'JIRAProjectKey' : projectKey};
      if (Object.keys(data).length > 0 amp;amp; data.QuickJIRAs ) {
        data.QuickJIRAs.push(objectToAdd);
        localQuickJiraArray.push(objectToAdd);

      } else {
        data.QuickJIRAs = [objectToAdd];
        localQuickJiraArray = [objectToAdd];
      }

      baseURLInput.value = ""
      boardNameInput.value = ""
      projectKeyInput.value = ""
      saveNewFormData();
      chrome.storage.sync.set(data, function() {
        drawCurrentQuickJIRATable();
        // logStorage();
      });
    });
  }

}

function checkIfInputDataDoesExist(baseURL, boardName, projectKey) {

  if (localQuickJiraArray.length != 0) {
    //check for existing baseURL and board name; set doesExist to true if one does
    //Removed checking for Base URL's since it's possible there are multiple projects on the same URLs

    for (var i = 0; i < localQuickJiraArray.length; i  ) {
      var existingJiraBoardID = localQuickJiraArray[i].JIRABoardName;
      var existingJiraBoardBaseURL = localQuickJiraArray[i].JIRABaseURL;
      var existingJiraProjectKey = localQuickJiraArray[i].JIRAProjectKey;
      if (boardName == existingJiraBoardID) {
        alert("Looks like you already a QuickJIRA with that Name. n n Please try adding a your Quick JIRA with a new name");
        return Boolean(true);
      } else if (projectKey == existingJiraProjectKey) {
        alert("Looks like you already a QuickJIRA with that Project Key. n n Please try adding a your Quick JIRA with a newJIRAProjectKey");
        return Boolean(true);
      }else {
        return Boolean(false);
      }
    }
  } else {
    return Boolean(false);
  }

}

function validateBaseURL(baseURLInput) {
  var regexQuery = "^(https?://)?(www\.)?([-a-z0-9]{1,63}\.)*?[a-z0-9][-a-z0-9]{0,61}[a-z0-9]\.[a-z]{2,6}(/[-\w@\ \.~#\?amp;/=%]*)?$";
  var regexTest = new RegExp(regexQuery, 'i');
  var isValidURL = regexTest.test(baseURLInput);

  if (isValidURL == true) {
    var arrayOfMatches = baseURLInput.match(/.*/(.*)$/);
    if (arrayOfMatches.length < 2 || arrayOfMatches[1].toLowerCase() != "browse") {
      var confirmURL = confirm("Are you sure you want to Add this URL? n n Quick Ticket works best when the last part of the URL is `/browse` !");
      if (confirmURL == true) {
        return baseURLInput;
      } else {
        throw new Error("User did not want to add this URL");
      }
    } else {
      return baseURLInput;
    }

  } else {
    alert("That doesn't look like valid JIRA URL. n n Please enter a valid URL n n URLs should not contain Project Keys");
    throw new Error("invalid JIRA entered");
  }

}

function validateBoardName(boardNameInput) {
  if (boardNameInput.length < 50) {
    var regexQuery = "^[A-Za-z0-9 _]*[A-Za-z0-9][A-Za-z0-9 _]*$";
    var regexTest = new RegExp(regexQuery, 'i');
    var isValidBoardNameInput = regexTest.test(boardNameInput);

    if (isValidBoardNameInput == true) {
      return boardNameInput;
    } else {
      alert("That doesn't look like valid Board Name. n n Project Keys may only contain letters and numbers");
      throw new Error("invalid Board Name Add Attempt");
    }
  } else {
    alert("That doesn't look like valid Board Name. n n Please enter a Board Name less than 50 characters");
    throw new Error("invalid Board Name Add Attempt");
  }

}

function validateProjectKey(projectKeyInput) {
  if (projectKeyInput.length < 50) {
    var regexQuery = "^[A-Z][A-Z_0-9] ";
    var regexTest = new RegExp(regexQuery);
    var isValidProjectKeyInput = regexTest.test(projectKeyInput);
    if (isValidProjectKeyInput == true) {
      return projectKeyInput;
    } else {
      alert("That doesn't look like valid Project Key. n n Project Keys may only contain Uppercase letters, numbers, and '_' ");
      throw new Error("invalid Project Key Add Attempt");
    }
  } else {
    alert("That doesn't look like valid Project Key. n n Please enter a Project Key less than 50 characters");
    throw new Error("invalid Project Key Add Attempt");
  }

}

function toggleAddNewQuickJIRA(shouldDisplay) {
  var newFormDiv = document.getElementById("addNewForm");
  var newFormButton = document.getElementById("toggleAddNewButton");
  if (shouldDisplay == false) {
    newFormDiv.style.display = "none";
    addNewQuickJIRAIsShown = false;
    newFormButton.value="Add New"
  } else if (shouldDisplay == true) {
    newFormDiv.style.display = "block";
    addNewQuickJIRAIsShown = true;
    newFormButton.value="Hide"
  } else {
    if (newFormDiv.style.display == "block") {
      newFormDiv.style.display = "none";
      addNewQuickJIRAIsShown = false;
      newFormButton.value="Add New"
    } else {
      newFormDiv.style.display = "block";
      addNewQuickJIRAIsShown = true;
      newFormButton.value="Hide"
    }
  }
}


// Log Storage for debugging
function logStorage() {
    if(chrome.storage) {
        chrome.storage.local.get(function(data){
            console.log("chrome.storage.local:");
            if(chrome.runtime.lastError) {
                console.error(chrome.runtime.lastError);
            } else {
                console.log(data);
            }
            chrome.storage.sync.get(function(data){
                console.log("chrome.storage.sync:");
                if(chrome.runtime.lastError) {
                    console.error(chrome.runtime.lastError);
                } else {
                    console.log(data);
                }
            });
        });
    } else {
        console.warn("chrome.storage is not accessible, check permissions");
    }
}
 

всплывающее окно-css

 h1 {
  margin: 0px;
  font-size: 12pt;
}

body {
  width: 600px;
  margin: 0px;
  z-index: 1;
}

.header {
  display: inline-block;
  min-width: 570px;
}

.header h1{
  margin: 0;
  display: inline-block;
  float: left;
}

.header .QuickJIRAcontrols {
  float: right;
  width: 275px;
  margin-right: -5px;
  text-align: center;
}

#toggleAddNewButton, #optionsButton {
  display: inline-block;
  margin: 0;
  padding: 0;
  height: 19px;
  width: 130px;
}
#optionsButton {
  float: left;
  color: black;
}

#optionsButton:hover {
  background-color: #7B7B7B;
  color: #FFFFFF;
}

#toggleAddNewButton {
  float: right;
}

.addNewForm {
  display: block;
}
.NewJIRAForm {
  min-width: 100%;
  background-color: #D8D8D8;
  padding: 15px;
  padding-top: 20px;
}

.NewJIRAForm input[type=text] {
  width: 375px;
}

.NewJIRAForm input[type=button] {
  padding: 0px;
  width: 170px;
  margin-left: 15px;
  color: #7ED321;
}

.NewJIRAForm input[type=button]:hover {
  color: #FFFFFF;
  background-color: #7ED321;
}

input[type=button]:focus, button:focus, input[type=text]:focus {
  outline: none;
}
#newJIRAProjectKey {
  padding-left: 10px;
  width: 160px;
  margin-left: 15px;
}

input[type=button], button {
  height: 38px;
  border-radius: 6px;
  border-style: none;
  font-size: 12px;
  font-weight: bold;
}

.newJIRABoardNameInputField, .newJIRABaseURLField, .newJIRABoardKeyInputField {
  height: 36px;
  border-radius: 6px;
  border-style: none;
  padding-left: 10px;
}

.goToInput {
  height: 36px;
  border-radius: 6px;
  padding-left: 10px;
  width: 130px;
  border-style: solid;
  margin-right: 15px;
}

.addFirstRowForm, .addSecondRowForm {
  margin-top: 15px;
}

.goNewButton, .goCurrentButton {
  margin-right: 15px;
  background-color: #7ED321;
  color: white;
  width: 90px;
}

.goNewButton:hover, .goCurrentButton:hover {
  background-color: #417505;
}

.removeButton {
  background-color: #D0021B;
  color: white;
  width: 65px;
}

.removeButton:hover {
  background-color: #961424;
}

.removeButton:focus, .goNewButton:focus, .goCurrentButton:focus {
  outline: 0;
}

.quickJIRARow {
  margin-left: 15px;
  margin-top: 7.5px;
  z-index: 2;
  display: inline-block;
}

.CurrentQuickJIRAs .quickJIRARow:last-child {
  margin-bottom: 7.5px;
}

.quickJIRARowButtons {
  display: inline-block;
}

.CurrentQuickJIRAs {
  max-height:255px;
  overflow-y:scroll;
}

.quickJIRARow a {
  text-decoration: none;
  color: #000;
  text-align: right;
  display: inline-block;
  white-space: nowrap;
  width: 130px;
  margin-right: 10px;
  font-weight: bold;
  font-size: 12px;
  z-index: 2;
  overflow: hidden;
  text-overflow: ellipsis;
  vertical-align: middle;
  position: relative;
}

.quickJIRARow a:hover {
  color: blue;
}
 

Ссылка на репозиторий (текущая проблема, воспроизводимая в master): https://github.com/bzellman/quickJira

Комментарии:

1. Звучит как ошибка. См . crbug.com и сообщите об этом, если это не зафиксировано в Canary и нет никаких предыдущих отчетов.

2. Спасибо! Perforce немного лучше в Canary. Я подниму эту проблему, если не смогу найти соответствующий запрос и постараюсь минимизировать влияние на мою сторону

3. то же самое происходит и со мной — вы отправили отчет об ошибке?

4. Привет, извините за поздний ответ здесь. Похоже, что с аналогичными строками уже был отправлен отчет об ошибке bugs.chromium.org/p/chromium/issues/detail?id=971701