editoria11y-1.0.0-alpha8/modules/editoria11y_csa/js/crawler.js

modules/editoria11y_csa/js/crawler.js
let ed11yCrawlOnce = false;

Drupal.behaviors.editoria11yAdmin = {
  attach: function (context, settings) {
    "use strict";

    if (ed11yCrawlOnce) {
      return;
    }
    ed11yCrawlOnce = true;

    const crawlControls = document.getElementById('crawl-controls');
    if (document.querySelector('.views-edit-view, #views-edit-form') || !crawlControls) {
      return;
    }

    const filters = document.querySelector('.view-filters > form');
    if (filters) {
      const details = document.createElement('details');
      // @todo 3.0 test and style in Gin admin theme.
      details.classList.add('claro-details', 'ed11y-filters');
      const summary = document.createElement('summary');
      summary.classList.add('claro-details__summary');
      summary.textContent = Drupal.t('Filter which pages will be crawled');
      details.appendChild(summary);
      if (document.querySelector('#edit-reset')) {
        details.open = true;
      }
      filters.insertAdjacentElement('beforebegin', details);
    }

    const urlParams = new URLSearchParams(window.location.search);
    let paused = false;

    const wrapper = document.querySelector('.editoria11y-crawl');
    let progress = document.querySelector('.editoria11y-crawl progress');
    const currentPage = progress.value ?? 1;
    const maxPage = progress.max ?? 1;
    const itemsPerPage = 50;

    const progressWrap = document.createElement('div');
    progressWrap.classList.add('progress');
    const progressLabel = document.createElement('div');
    progressLabel.classList.add('progress__label');
    const progressTrack = document.createElement('div');
    progressTrack.classList.add('progress__track');
    const progressBar = document.createElement('div');
    progressBar.classList.add('progress__bar');
    const progressPercent = document.createElement('div');
    progressPercent.classList.add('progress__percentage');
    const progressDescription = document.createElement('div');
    progressDescription.classList.add('progress__description');
    progressTrack.appendChild(progressBar);
    progressWrap.append(progressLabel, progressTrack, progressPercent, progressDescription);
    crawlControls.insertAdjacentElement('afterend', progressWrap);

    const exit = document.getElementById('crawl-done');
    exit.textContent = Drupal.t('Cancel');


    const frameBucket = document.createElement('div');

    const statusBar = document.createElement('div');
    const crawlSpeed = document.createElement('select');
    crawlSpeed.name = 'crawlSpeed';
    crawlSpeed.id = 'crawlSpeed-select';
    crawlSpeed.setAttribute('aria-describedby', 'slow-warning');
    crawlSpeed.classList.add('form-select', 'form-element', 'form-element--type-select');
    const speed = urlParams.get('speed') ?? '500';
    const createOption = function (val) {
      const option = document.createElement('option');
      option.value = val;
      option.textContent = val;
      if (val === speed) {
        option.selected = 'true';
      }
      crawlSpeed.appendChild(option);
    };
    const speeds = [
      '100', '250', '500', '1000', '2500', '5000'
    ];
    speeds.forEach((speed) => createOption(speed));
    const speedBlock = document.createElement('div');
    speedBlock.classList.add('views-exposed-form__item', 'js-form-item', 'form-item', 'js-form-type-select', 'form-type--select', 'js-form-item-type', 'form-item--type');
    const speedLabel = document.createElement('label');
    speedLabel.for = 'crawlSpeed-select';
    speedLabel.classList.add('form-item__label');
    speedLabel.textContent = Drupal.t('Millisecond pause between page requests');
    speedBlock.appendChild(crawlSpeed);
    speedBlock.appendChild(speedLabel);
    statusBar.prepend(speedBlock);
    crawlControls.append(statusBar);


    const estimate = document.createElement('p');
    const estimateLabel = document.createElement('span');
    estimateLabel.textContent = Drupal.t('Estimated time:') + ' ';
    estimate.appendChild(estimateLabel);
    const speedVal = document.createElement('span');
    estimate.appendChild(speedVal);
    statusBar.appendChild(estimate);
    const slow = document.createElement('div');
    slow.id = 'slow-warning';
    const slowEm = document.createElement('strong');
    slow.appendChild(slowEm);
    estimate.appendChild(slow);

    let pageLoad = 100;
    const observer = new PerformanceObserver((list) => {
      list.getEntries().forEach((entry) => {
        if (entry.entryType === 'navigation' && entry.duration > 100) {
          pageLoad = entry.duration;
          estimateTime();
        }
      });
    });
    observer.observe({ type: 'navigation', buffered: true });

    const slowWarning = Drupal.t('Remember that this browser window needs to stay open until the crawl finishes! If that is too long, consider selecting a subset of the pages below.');
    const estimateTime = function() {
      // 50 items per page, times speed, plus ~3 seconds lag.
      let desiredSpeed = parseInt(crawlSpeed.value);
      const likelySpeed = desiredSpeed < pageLoad ? (pageLoad * 2 + desiredSpeed) / 3  : desiredSpeed;
      const seconds = ((maxPage * itemsPerPage * likelySpeed) - ((currentPage - 1) * itemsPerPage * likelySpeed) + (maxPage * 10000)) / 1000;
      let speed;
      if (seconds > 120 * 60) {
        speed = Math.ceil(seconds / 3600) + ' ' + Drupal.t('hours');
      } else if (seconds > 60) {
        speed = Math.ceil(seconds / 60) + ' ' + Drupal.t('minutes');
      } else {
        speed = '1 ' + Drupal.t('minute');
      }
      speedVal.textContent = speed;
      slowEm.textContent = seconds > 600 ? slowWarning : '';
    };
    estimateTime();
    crawlSpeed.addEventListener('change', () => {
      estimateTime();
    });


    let urls = [];
    const rows = Array.from(document.querySelectorAll('.editoria11y-crawl .crawl-url a'));
    rows.forEach((link) => {
      urls.push(link.href);
    });
    const maxRows = urls.length;
    const totalMax = (maxPage - 1) * itemsPerPage + maxRows;
    window.ed11ySynced = 0;

    const buttonStart = document.createElement('button');
    const progValue = document.createElement('span');
    buttonStart.textContent = Drupal.t('Start crawling');
    buttonStart.classList.add('button', 'button--primary');
    crawlControls.prepend(buttonStart);


    const updateProgValue = () => {
      const current = (currentPage - 1) * itemsPerPage + (maxRows - urls.length) + 1;
      const percent = Math.round(100 * current / totalMax);
      progressDescription.textContent = `${Drupal.t('Checked:')} ${current} / ${totalMax} ${Drupal.t('pages')}`;
      progressBar.style.setProperty('width', `${percent}%`);
      progressPercent.textContent = `${percent}%`;
    };

    let progressOnce;
    const initProgressTracker = () => {
      if (progressOnce) {
        return;
      }
      progressOnce = true;
      frameBucket.id = 'frame-bucket';
      wrapper.insertAdjacentElement('beforeend', frameBucket);
      updateProgValue();
    };

    const startButton = function() {
      if (buttonStart.dataset.state !== 'crawling') {
        paused = false;
        buttonStart.textContent = 'Pause crawl';
        buttonStart.dataset.state = 'crawling';
        wrapper.classList.remove('paused');
        wrapper.classList.add('crawling');
      } else {
        paused = true;
        buttonStart.textContent = 'Resume crawl';
        buttonStart.dataset.state = 'paused';
        wrapper.classList.add('paused');
      }
      initProgressTracker();
      crawl();
    };

    buttonStart.addEventListener('click', () => startButton() );

    const nextPage = () => {
      if (window.ed11ySynced > 0) {
        window.setTimeout(()=> {
          // Wait up to 20s for the last frames to finish.
          window.ed11ySynced = window.ed11ySynced - 0.0125;
          nextPage();
        }, 250);
        return;
      }
      if (paused) {
        return;
      }
      const nextPager = document.querySelector('.pager [rel="next"]');
      if (nextPager) {
        window.setTimeout(function() {
          if (nextPager.href.indexOf('&speed') === -1) {
            nextPager.href = nextPager.href + `&speed=${crawlSpeed.value}`;
          } else {
            const url = new URL(nextPager.href);
            const addParams = {
              speed: `${crawlSpeed.value}`
            };
            const newParams = new URLSearchParams([
              ...Array.from(url.searchParams.entries()),
              ...Object.entries(addParams),
            ]).toString();
            nextPager.href = new URL(`${url.origin}${url.pathname}?${newParams}`);
          }
          nextPager.click();
        }, 1000);
      } else {
        // Done.
        wrapper.classList.add('done');
        wrapper.classList.add('paused');
        buttonStart.removeEventListener('click', () => startButton() );
        exit.classList.add('button', 'button--primary');
        exit.textContent = Drupal.t('Start new crawl');
        exit.focus();
      }
    };

    const crawl = () => {
      if (paused) {
        return;
      }
      if (window.ed11ySynced > 2) {
        window.setTimeout(()=> {
          const notMarkedFrames = document.querySelectorAll('.frame-bucket iframe:not(.loaded)');
          notMarkedFrames.forEach((frame) => {
            frame.classList.add('loaded');
          });
          // If we're stuck for more than 20s, give up and move on.
          window.ed11ySynced = window.ed11ySynced - 0.0125;
          crawl();
        }, parseInt(crawlSpeed.value));
        return;
      }

      window.setTimeout(() => {
        updateProgValue();
        const url = urls.shift();
        const newFrame = document.createElement('iframe');
        newFrame.width = (100 / totalMax) + '%';
        window.ed11ySynced++;
        newFrame.classList.add('loading');
        newFrame.addEventListener('load', function() {
          newFrame.classList.add('loaded');
        });
        newFrame.setAttribute('src', url);
        frameBucket.appendChild(newFrame);
        if (urls.length > 0) {
          crawl();
        } else {
          nextPage();
        }

      }, parseInt(crawlSpeed.value));
    };


    if (parseInt(progress.getAttribute('value')) !== 1) {
      buttonStart.click();

    } else {
      progress.setAttribute('hidden', 'true');
    }
  }
};

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc