Javascript-форум (https://javascript.ru/forum/)
-   Javascript под браузер (https://javascript.ru/forum/css-html/)
-   -   Выгрузка кода соседней вкладки Chrome, работа с ней (https://javascript.ru/forum/css-html/72011-vygruzka-koda-sosednejj-vkladki-chrome-rabota-s-nejj.html)

kirsan94 29.12.2017 03:50

Выгрузка кода соседней вкладки Chrome, работа с ней
 
Доброго времени суток!
Начал изучать JS(вот прям только-только начал, сегодня), с целью написать скрипт для легкого упрощения работы себе и коллегам (мониторинг).
Не прошу написать мне весь код(хотя против помощи любого размера я не буду уж точно), просто подсказку/наводку/хинт)
Цель изначально такая - есть некая система обработки входящих обращений/системных инцидентов HPSM(написана на JS по словам коллег), есть у нее интерфейс, и частью этого интерфейса является отображение обращений в определенном статусе (т.е. я вижу строки таблицы, на которые могу нажать и перейти к конкретному обращению). Так-же на этой-же странице есть кнопка, которая отдельно этот список обновляет, без обновления самой страницы. Задача - html страницу, которая будет выгружать код вкладки (допустим она всегда первая) браузера с этим всем HPSM, затем выделять из этого кода отдельный кусок, который всегда на своем месте лежит, и выводить на себя. Совсем уж мечта - что-бы этот скрипт раз в 5 минут "прожимал" кнопку обновления списка на той вкладке, а затем просматривать все тот-же кусок кода, и при изменениях алерт выводить.

Есть-ли вообще возможность реализовать все это на JS? Или нужно использовать что-то другое? Может подскажите направление/функции?
Буду очень благодарен за любую помощь) Очень хочется облегчить работу нашему мониторингу):help:

Aetae 29.12.2017 23:16

Всё возможно.
Прикрепи чтоль сохранённую ту самую страничку, посмотрим.

А так способа два: 1. userscript - для этого придётся ставить расширение для браузера, 2. букмарклет - закладка при клике на которую запускается код.

kirsan94 31.12.2017 13:11

Aetae, странная тема, отображение в "просмотр кода" и "просмотр кода страницы"(который в новой вкладке открывается) несколько отличается.
Полностью я страницу не могу скинуть (у нас СБ очень злые, вонзят по самые гланды), но есть скрины нужной секции страницы.
На странице у меня отображаются обращения, подходящие по определенному шаблону.
Первый - когда этих "обращений" нет:


Второй - когда они есть:



По скринам видно, что при появлении в списке обращений, в класса "x-grid3-body" появляется вложенный класс (не знаю как на терминах это называется) с длиннющим названием, и кучей вложений (элементы таблицы разные, ссылки и т.д. что уже не важно. Важно что внутри "body" появляется класс, который является своеобразной строкой таблицы, по сути самим обращением в этом списке. Именно это место и интересно.
ID у класса меняется каждый раз при обновлении списка, так что от него отталкиваться не выйдет, нужно отталкиваться от наличия классов в классе "x-grid3-body".

Вот, кстати, код той самой кнопки "Обновить", которая обновляет список обращений:



P.S.: не работает
[spoiler] 1 [/spoiler]
как на этом форуме спойлеры ставить?

Aetae 31.12.2017 16:58

Это печально.
Приложение написано на ExtJS - овермайндном корпоративном бегемоте, "простенько" с ним нифига не сделаешь.

Вот накидал букмарклет который теоретически должен делать то что надо, но если там ещё и сложная структура вложенных фреймов, то без прямого доступа до той страницы уже ничего не поделаешь:
(function(){
  var w = window.open('', 'monitoring_window');
  w.document.open();
  w.document.write(`<!DOCTYPE html>
  <html>
  <head>
    <title>monitor</title>
    <style>
      #error{
        background:red;
        color:white;
      }
	  /* здесь придётся добавить стилей для нормального отображения результата */
    </style>
  </head>
  <body>
  <div id="error"></div>
  <div id="result"></div>
  <script>
    var buttonPressInterval = 5 * 60 * 1000; /* интервал повтора нажатия в мс */
    var contentUpdateInperval = 1000; /* интервал обновления данных */
    var errorElement = document.getElementById('error'); /* сюда выводим ошибки */
    var resultElement = document.getElementById('result');  /* сюда выводим результат */

    var buttonSelector = 'button[aria-label="Обновить"]'; /* селектор для кнопки */
    var contentSelector = '.x-grid3-body'; /* селектор для нужного */

    var lastButtonPress = 0;

    function simulateClick(window) {
      /*
        Имитация нажатия, поднятия и клика, 
        неизвестно на что именно прописано событие конкретно у вас,
        можно поэксперементировать и убрать лишнее.
      */
	  var button = window.document.querySelector(buttonSelector);
	  if(!button) return false;
	  
      var event = window.MouseEvent, options = {
        bubbles: true,
        cancelable: true,
        view: window
      };

      button.dispatchEvent(new event('mousedown', options));
      button.dispatchEvent(new event('mouseup', options));
      button.dispatchEvent(new event('click', options));
      return true;
    }

    function show(html, element){
      if(element.showHTML === html) return false;
      element.innerHTML = html;
    }

    (function update(){
      try{
        var element = opener.document.querySelector(contentSelector);
        if(element){
          show(element.innerHTML, resultElement);
        }  
      }catch(e){
        return show(
          'Потеряна связь с главной страницей, перезапустите букмарклет.', 
          errorElement
        );
      }
      
      if(new Date() - lastButtonPress >= buttonPressInterval){
        show(
          simulateClick(opener) ? '' : 'Не найдена кнопка обновления.', 
          errorElement
        );
        lastButtonPress = new Date().getTime();
      }
      
      setTimeout(update, contentUpdateInperval)
    }());
  </script>
  </body>
  <html>`);
  w.document.close();
}())


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

kirsan94 31.12.2017 17:50

Спасибо за помощь)
Сделал по вашей инструкции, но страница почему-то пустая, поле result пустое, при этом обращения есть.





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

Aetae 31.12.2017 18:11

document.querySelectorAll(".x-grid3-body").length что выдаёт?
Если больше 1, то значит класс не уникален, сделай в инструментах разработчика на нужном элементе Копировать -> Селектор и подставь полученное значение в contentSelector.

kirsan94 31.12.2017 18:15

честно говоря не знаю где посмотреть(
в коде букмарклета такой строки нет, полагаю это какой-то параметр у страницы?

Aetae 31.12.2017 18:16

В консоли(соседняя вкладка в инструментах разраотчика).
Кстати если 0, то значит в деле замешаны фреймы и всё печально.

kirsan94 31.12.2017 18:22

в консоли вот такая картина

Aetae 31.12.2017 18:23

Это всё фигня, открой консоль на главной странице, введи туда document.querySelectorAll(".x-grid3-body").length и нажми enter.

kirsan94 31.12.2017 18:25

Да, я понял что тупанул)
Увы, там 0.
Запускал на обеих страницах

Aetae 31.12.2017 18:28

Ну посмотри тогда вверх от нужно элемента встречается ли там в родителях iframe или frame, единожды или несколько раз, есть ли у него src?

kirsan94 31.12.2017 18:33

Да, есть такой, и src тоже, detail.do?lang=ru, который является ссылкой на https://sm.mos.ru/sm/detail.do?lang=ru

kirsan94 31.12.2017 18:43

Эта ссылка выдает в отдельной вкладке вот эту часть основной страницы:

причем в том состоянии, в котором она находится на основной странице, т.е. если я меняю значения на основной, и обновляю страницу по этой ссылке, то её содержимое меняется соответственно.

Aetae 31.12.2017 19:06

(function(){
  var w = window.open('', 'monitoring_window');
  w.document.open();
  w.document.write(`<!DOCTYPE html>
  <html>
  <head>
    <title>monitor</title>
    <style>
      #error{
        background:red;
        color:white;
      }
      /* здесь придётся добавить стилей для нормального отображения результата */
    </style>
  </head>
  <body>
  <div id="error"></div>
  <div id="result"></div>
  <script>
    var buttonPressInterval = 5 * 60 * 1000; /* интервал повтора нажатия в мс */
    var contentUpdateInperval = 1000; /* интервал обновления данных */
    var errorElement = document.getElementById('error'); /* сюда выводим ошибки */
    var resultElement = document.getElementById('result');  /* сюда выводим результат */
 
    var buttonSelector = 'button[aria-label="Обновить"]'; /* селектор для кнопки */
    var contentSelector = '.x-grid3-body'; /* селектор для нужного */
 
    var lastButtonPress = 0;
	
	function querySelectorAnyFrame(window, selector){
	  var element;
	  if(element = window.document.querySelector(selector)) 
		return element;
      for(var i = window.frames.length, element; i--;){
        try{
          if(element = window.frames[i].document.querySelector(selector)){
            return element
          }
        }catch(e){}
      }
    }
 
    function simulateClick(window) {
      /*
        Имитация нажатия, поднятия и клика,
        неизвестно на что именно прописано событие конкретно у вас,
        можно поэксперементировать и убрать лишнее.
      */
      var button = window.document.querySelector(buttonSelector);
      if(!button) return false;
       
      var event = window.MouseEvent, options = {
        bubbles: true,
        cancelable: true,
        view: window
      };
 
      button.dispatchEvent(new event('mousedown', options));
      button.dispatchEvent(new event('mouseup', options));
      button.dispatchEvent(new event('click', options));
      return true;
    }
 
    function show(html, element){
      if(element.showHTML === html) return false;
      element.showHTML = element.innerHTML = html;
    }
 
    (function update(){
      try{
        var element = querySelectorAnyFrame(opener, contentSelector);
        if(element){
          show(element.innerHTML, resultElement);
        } 
      }catch(e){
        return show(
          'Потеряна связь с главной страницей, перезапустите букмарклет.',
          errorElement
        );
      }
       
      if(new Date() - lastButtonPress >= buttonPressInterval){
        show(
          simulateClick(opener) ? '' : 'Не найдена кнопка обновления.',
          errorElement
        );
        lastButtonPress = new Date().getTime();
      }
       
      setTimeout(update, contentUpdateInperval)
    }());
  </script>
  </body>
  <html>`);
  w.document.close();
}())

Попробуй так, но тут уж никаких гарантий...

kirsan94 31.12.2017 19:18

ВАУ!

Спасибо большое) Вы волшебник)
Подучу JS, заставлю это дело звуки издавать при появлении обращений)
Это, кстати, возможно, именно звук воспроизводить?
Если я правильно понимаю, принципе нужно сохранять состояние element в переменную, и в функции update сравнивать со старым, с вызовом отдельной функции при отличии.

Aetae 31.12.2017 19:21

Да, моджно. HTML5 елемент audio.
Ток звуки надоедают. В своё время хорошо помогала засветка всего экрана красным/желтым на секунду.)
Но это уж сами. Эксперементируйте в консоли, после чего уже добавляйте в рабочий код.

kirsan94 31.12.2017 19:23

Огромное спасибо!
С наступающим! (Или уже наступившим)
Думаю можно закрывать)

Aetae 31.12.2017 19:25

Цитата:

Сообщение от kirsan94 (Сообщение 474083)
Если я правильно понимаю, принципе нужно сохранять состояние element в переменную, и в функции update сравнивать со старым, с вызовом отдельной функции при отличии.

Собсно оно и сейчас уже так делает(element.showHTML === html - сравнение нового со старым), и не обновляет если нет изменений. Вроде бы мелочь, но когда пытаешься скопировать а выделение постоянно сбрасывается - начинаешь думать от таких мелочах.)

..upd
Кстати поправил баг, старый результат в этой функции не сохранялся.))

kirsan94 31.12.2017 19:27

А можно как-то заставить его прожимать на основной странице ту самую кнопку "Обновить"?
Я так понял нужно уже разбираться с simulateClick, и как местный интерфейс заставить с ним работать?

Aetae 31.12.2017 19:31

Цитата:

Сообщение от kirsan94 (Сообщение 474087)
А можно как-то заставить его прожимать на основной странице ту самую кнопку "Обновить"?
Я так понял нужно уже разбираться с simulateClick, и как местный интерфейс заставить с ним работать?

Теоретически он и сейчас это делает, раз в 5 минут как и было заказано.
Поменяйте:
var buttonPressInterval = 5 * 60 * 1000;
на поменьше, для экспериментов.

Для это кстати не обязательно перезапускать всё, можно на открытой странице "monitoring" прям в консоли написать например "buttonPressInterval = 1000;"

На счёт "ручного нажатия" на кнопку - там же "simulateClick(window.opener)".

kirsan94 31.12.2017 19:40

Да, я вот тоже вспомнил про этот момент, и изменил на 5*2*1000)
simulateClick(window.opener) выдает true, но на основной странице изменений нет
Если вручную нажимать на основной эту кнопку, то в консоли выдает вот это:

Aetae 31.12.2017 20:09

В консоли на главной document.querySelector('button[aria-label="Обновить"]') и наведи на результат мышь. Подсветилась нужная кнопка?

kirsan94 31.12.2017 20:32

Выдало
<button type="button" id="ext-gen-top20" class=" x-btn-te on-refresh cwc-toolbar-refresh" aria-label="Обновить">Обновить</button>

но кнопка не высвечивается

зато высвечивается если во вкладке elements навести на
<tbody class="x-btn-small x-btn-icon-small-left"><tr><td class="x-btn-tl"><i>&nbsp;</i></td><td class="x-btn-tc"></td><td class="x-btn-tr"><i>&nbsp;</i></td></tr><tr><td class="x-btn-ml"><i>&nbsp;</i></td><td class="x-btn-mc "><em class="" unselectable="on"><button type="button" id="ext-gen-top435" class=" x-btn-text" aria-label="Обновить" style="background-image: url(&quot;images/toolbar/trefresh.png&quot;);">Обновить</button></em></td><td class="x-btn-mr"><i>&nbsp;</i></td></tr><tr><td class="x-btn-bl"><i>&nbsp;</i></td><td class="x-btn-bc"></td><td class="x-btn-br"><i>&nbsp;</i></td></tr></tbody>

Aetae 31.12.2017 20:45

Проверь в консоли
document.querySelectorAll('button.x-btn-text[aria-label="Обновить"][style*="images/toolbar/trefresh.png"]')
Если результат только один, то поменяй
25     var buttonSelector = 'button[aria-label="Обновить"]';
на
var buttonSelector = 'button.x-btn-text[aria-label="Обновить"][style*="images/toolbar/trefresh.png"]';

Если ничего не выдало, то поменяй ещё и
49     var button = window.document.querySelector(buttonSelector);
на
var button =  querySelectorAnyFrame(window, buttonSelector);



Гадание на кофейной гуще - сложная вещь.)

kirsan94 31.12.2017 20:50

Понял в чем суть, в консоли он выдает id = "ext-gen-top20"
а на самой странице он ext-gen-top539, причем с каждым нажатием на эту кнопку, и соответственно обновлением страницы, число увеличивается
спустя 4 обновления это уже 617

kirsan94 31.12.2017 21:06

он выдал надпись, но я с телефона через team wiever сижу, немного не удобно. через 10 минут скину скрин, оно выдало
NodeList [button#ext-gen-top669.x-btn-text]
0
:
button#ext-gen-top669.x-btn-text
length
:
1
__proto__
:
NodeList

при наведении на вторую строку button выделяется нужная кнопка
скрин через 5 минут

Aetae 31.12.2017 21:16

length:1
"Длина один" - по русски. С смело зафигачивай первый вариант.)

kirsan94 31.12.2017 21:19

Так, при вводе команды выводит вот это:

при наведении на него ничего не выделяется

Но, если на это нажать, оно раскроется:

и вот если тут навести на выделенный светло-синим элемент (выделил отдельно синими чертами), то выделяется искомая кнопка!

kirsan94 31.12.2017 21:27

Aetae, вы наш Дед-Мороз)
Все работает, обновление идет)
От лица всего коллектива мониторинга ЦОД огромное вам человеческое спасибо) Лучший подарок на этот НГ :D
Спасибо большое за терпение, и помощь в облегчении службы честному мониторингу) (теперь у нас больше времени писать отчеты? что реально радует :D)

Aetae 31.12.2017 21:31

Вообще ты не воспринимай код как магию, по большей он сам за себя говорит, пусть и на английском, например:
window.document.querySelector(buttonSelector);
В окне из документа запросить селектор взятый из переменной buttonSelector

button[aria-label="Обновить"]
Элемент "button" с атрибутом aria-label равным "Обновить"


button.x-btn-text[aria-label="Обновить"][style*="images/toolbar/trefresh.png"]
Элемент "button" с классом "x-btn-text", атрибутом "aria-label" равным "Обновить" и атрибутом "style" содержащим "images/toolbar/trefresh.png"

Собсно первый вариант не работал потому что querySelector(в отличие от querySelectorAll)запрашивает самый первый из подходящих под селектор элементов. А первый селектор оказался слишком общим и цеплял ещё какую-то кнопку.

А так я сам в мониторинге крупного провайдера в своё время работал.:)

kirsan94 31.12.2017 21:37

Ну, я код изучал только в университете, и только базовые какие-то функции в php, c, c#, fasm, и капелька js с приложения на телефон)
Так что для меня это немного магия)
Я понимаю принципы работы, но сам язык не знаю)
Вот, кстати, и новогоднее настроение подъехало) Вы мне сегодня магии завезли, так необходимой)


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