github.com/pf-qiu/concourse/v6@v6.7.3-0.20201207032516-1f455d73275f/web/public/elm-setup.js (about)

     1  const renderingModulePromise = import('./index.mjs');
     2  
     3  const node = document.getElementById("elm-app-embed");
     4  if (node === null) {
     5    throw "missing #elm-app-embed";
     6  }
     7  
     8  const app = Elm.Main.init({
     9    node: node,
    10    flags: window.elmFlags,
    11  });
    12  
    13  var resizeTimer;
    14  
    15  app.ports.pinTeamNames.subscribe(function(config) {
    16    const sections = () => Array.from(document.querySelectorAll("." + config.sectionClass));
    17    const header = (section) => Array.from(section.childNodes).find(n => n.classList && n.classList.contains(config.sectionHeaderClass));
    18    const body = (section) => Array.from(section.childNodes).find(n => n.classList && n.classList.contains(config.sectionBodyClass));
    19    const lowestHeaderTop = (section) => body(section).offsetTop + body(section).scrollHeight - header(section).scrollHeight;
    20  
    21    const pageHeaderHeight = () => config.pageHeaderHeight;
    22    const viewportTop = () => window.pageYOffset + pageHeaderHeight();
    23  
    24    const updateHeader = (section) => {
    25      var scrolledFarEnough = section.offsetTop < viewportTop();
    26      var scrolledTooFar = lowestHeaderTop(section) < viewportTop();
    27      if (!scrolledFarEnough && !scrolledTooFar) {
    28        header(section).style.top = "";
    29        header(section).style.position = "";
    30        body(section).style.paddingTop = "";
    31        return 'static';
    32      } else if (scrolledFarEnough && !scrolledTooFar) {
    33        header(section).style.position = 'fixed';
    34        header(section).style.top = pageHeaderHeight() + "px";
    35        body(section).style.paddingTop = header(section).scrollHeight + "px";
    36        return 'fixed';
    37      } else if (scrolledFarEnough && scrolledTooFar) {
    38        header(section).style.position = 'absolute';
    39        header(section).style.top = lowestHeaderTop(section) + "px";
    40        return 'absolute';
    41      } else if (!scrolledFarEnough && scrolledTooFar) {
    42        return 'impossible';
    43      }
    44    }
    45  
    46    const updateSticky = () => {
    47      document.querySelector("." + config.pageBodyClass).style.marginTop = pageHeaderHeight();
    48      sections().forEach(updateHeader);
    49    }
    50  
    51    clearTimeout(resizeTimer);
    52    resizeTimer = setTimeout(updateSticky, 250);
    53    window.onscroll = updateSticky;
    54  });
    55  
    56  app.ports.resetPipelineFocus.subscribe(function() {
    57    renderingModulePromise.then(({resetPipelineFocus}) => resetPipelineFocus());
    58  });
    59  
    60  app.ports.renderPipeline.subscribe(function (values) {
    61    const jobs = values[0];
    62    const resources = values[1];
    63    renderingModulePromise.then(({renderPipeline}) =>
    64      // elm 0.17 bug, see https://github.com/elm-lang/core/issues/595
    65      setTimeout(() => renderPipeline(jobs, resources, app.ports.newUrl), 0)
    66    );
    67  });
    68  
    69  app.ports.requestLoginRedirect.subscribe(function (message) {
    70    var path = document.location.pathname;
    71    var query = document.location.search;
    72    var redirect = encodeURIComponent(path + query);
    73    var loginUrl = "/login?redirect_uri="+ redirect;
    74    document.location.href = loginUrl;
    75  });
    76  
    77  
    78  app.ports.tooltip.subscribe(function (pipelineInfo) {
    79    const pipelineName = pipelineInfo[0];
    80    const pipelineTeamName = pipelineInfo[1];
    81  
    82    const team = document.getElementById(pipelineTeamName);
    83    if (team === null) {
    84      return;
    85    }
    86    const card = team.querySelector(`.card[data-pipeline-name="${pipelineName}"]`);
    87    if (card === null) {
    88      return;
    89    }
    90    const title = card.querySelector('.dashboard-pipeline-name');
    91    if(title === null || title.offsetWidth >= title.scrollWidth) {
    92      return;
    93    }
    94    title.parentNode.setAttribute('data-tooltip', pipelineName);
    95  });
    96  
    97  app.ports.tooltipHd.subscribe(function (pipelineInfo) {
    98    var pipelineName = pipelineInfo[0];
    99    var pipelineTeamName = pipelineInfo[1];
   100  
   101    const card = document.querySelector(`.card[data-pipeline-name="${pipelineName}"][data-team-name="${pipelineTeamName}"]`);
   102    if (card === null) {
   103      return;
   104    }
   105    const title = card.querySelector('.dashboardhd-pipeline-name');
   106  
   107    if(title === null || title.offsetWidth >= title.scrollWidth){
   108      return;
   109    }
   110    title.parentNode.setAttribute('data-tooltip', pipelineName);
   111  });
   112  
   113  app.ports.saveToLocalStorage.subscribe(function(params) {
   114    if (!params || params.length !== 2) {
   115      return;
   116    }
   117    const [key, value] = params;
   118    try {
   119      localStorage.setItem(key, JSON.stringify(value));
   120    } catch(err) {
   121      console.error(err);
   122    }
   123  });
   124  
   125  app.ports.saveToSessionStorage.subscribe(function(params) {
   126    if (!params || params.length !== 2) {
   127      return;
   128    }
   129    const [key, value] = params;
   130    try {
   131      sessionStorage.setItem(key, JSON.stringify(value));
   132    } catch(err) {
   133      console.error(err);
   134    }
   135  });
   136  
   137  app.ports.loadFromLocalStorage.subscribe(function(key) {
   138    const value = localStorage.getItem(key);
   139    if (value === null) {
   140      return;
   141    }
   142    setTimeout(function() {
   143      app.ports.receivedFromLocalStorage.send([key, value]);
   144    }, 0);
   145  });
   146  
   147  app.ports.loadFromSessionStorage.subscribe(function(key) {
   148    const value = sessionStorage.getItem(key);
   149    if (value === null) {
   150      return;
   151    }
   152    setTimeout(function() {
   153      app.ports.receivedFromSessionStorage.send([key, value]);
   154    }, 0);
   155  });
   156  
   157  app.ports.deleteFromLocalStorage.subscribe(function(key) {
   158    localStorage.removeItem(key);
   159  });
   160  
   161  
   162  const csrfTokenKey = "csrf_token";
   163  const favoritedPipelinesKey = "favorited_pipelines";
   164  window.addEventListener('storage', function(event) {
   165    if (event.key === csrfTokenKey || event.key === favoritedPipelinesKey) {
   166      const value = localStorage.getItem(event.key);
   167      setTimeout(function() {
   168        app.ports.receivedFromLocalStorage.send([event.key, value]);
   169      }, 0);
   170    }
   171  }, false);
   172  
   173  app.ports.syncTextareaHeight.subscribe(function(id) {
   174    const attemptToSyncHeight = () => {
   175      const elem = document.getElementById(id);
   176      if (elem === null) {
   177        return false;
   178      }
   179      elem.style.height = "auto";
   180      elem.style.height = elem.scrollHeight + "px";
   181  	return true;
   182    };
   183    setTimeout(() => {
   184      const success = attemptToSyncHeight();
   185      if (!success) {
   186  	  // The element does not always exist by the time we attempt to sync
   187  	  // Try one more time after a small delay
   188  	  setTimeout(attemptToSyncHeight, 50);
   189  	}
   190    }, 0);
   191  });
   192  
   193  let syncStickyBuildLogHeadersInterval;
   194  
   195  app.ports.syncStickyBuildLogHeaders.subscribe(function() {
   196    if (!CSS || !CSS.supports || !CSS.supports('position', 'sticky')) {
   197      return;
   198    }
   199    if (syncStickyBuildLogHeadersInterval != null) {
   200      return;
   201    }
   202    const attemptToSync = () => {
   203      const padding = 5;
   204      const headers = document.querySelectorAll('.build-step .header:not(.loading-header)');
   205      if (headers.length === 0) {
   206        return false;
   207      }
   208      headers.forEach(header => {
   209        const parentHeader = findParentHeader(header);
   210        let curHeight = 0;
   211        if (parentHeader != null) {
   212          const parentHeight = parsePixels(parentHeader.style.top || '') || 0;
   213          curHeight = parentHeight + parentHeader.offsetHeight + padding;
   214        }
   215        header.style.top = curHeight + 'px';
   216      });
   217      return true;
   218    }
   219  
   220    setTimeout(() => {
   221      const success = attemptToSync();
   222      if (!success) {
   223        // The headers do not always exist by the time we attempt to sync.
   224        // Keep trying on an interval
   225        syncStickyBuildLogHeadersInterval = setInterval(() => {
   226          const success = attemptToSync();
   227          if (success) {
   228            clearInterval(syncStickyBuildLogHeadersInterval);
   229            syncStickyBuildLogHeadersInterval = null;
   230          }
   231        }, 250);
   232      }
   233    }, 50);
   234  });
   235  
   236  function findParentHeader(el) {
   237    const closestStepBody = el.closest('.step-body');
   238    if (closestStepBody == null || closestStepBody.parentElement == null) {
   239      return;
   240    }
   241    return closestStepBody.parentElement.querySelector('.header')
   242  }
   243  
   244  function parsePixels(raw) {
   245    raw = raw.trim();
   246    if(!raw.endsWith('px')) {
   247      return 0;
   248    }
   249    return parseFloat(raw);
   250  }
   251  
   252  app.ports.scrollToId.subscribe(function(params) {
   253    if (!params || params.length !== 2) {
   254      return;
   255    }
   256    const [parentId, toId] = params;
   257    const padding = 150;
   258    const interval = setInterval(function() {
   259      const parentElem = document.getElementById(parentId);
   260      if (parentElem === null) {
   261        return;
   262      }
   263      const elem = document.getElementById(toId);
   264      if (elem === null) {
   265        return;
   266      }
   267      parentElem.scrollTop = offsetTop(elem, parentElem) - padding;
   268      setTimeout(() => app.ports.scrolledToId.send([parentId, toId]), 50)
   269      clearInterval(interval);
   270    }, 20);
   271  });
   272  
   273  function offsetTop(element, untilElement) {
   274    let offsetTop = 0;
   275    while(element && element != untilElement) {
   276      offsetTop += element.offsetTop;
   277      element = element.offsetParent;
   278    }
   279    return offsetTop;
   280  }
   281  
   282  app.ports.openEventStream.subscribe(function(config) {
   283    var buffer = [];
   284    var es = new EventSource(config.url);
   285    function flush() {
   286      if (buffer.length > 0) {
   287        app.ports.eventSource.send(buffer);
   288        buffer = [];
   289      }
   290    }
   291    function dispatchEvent(event) {
   292      buffer.push(event);
   293      if (buffer.length > 1000) {
   294        flush();
   295      }
   296    }
   297    es.onopen = dispatchEvent;
   298    es.onerror = dispatchEvent;
   299    config.eventTypes.forEach(function(eventType) {
   300      es.addEventListener(eventType, dispatchEvent);
   301    });
   302    app.ports.closeEventStream.subscribe(function() {
   303      es.close();
   304    });
   305    setInterval(flush, 200);
   306  });
   307  
   308  app.ports.checkIsVisible.subscribe(function(id) {
   309    var interval = setInterval(function() {
   310      var element = document.getElementById(id);
   311      if (element) {
   312        clearInterval(interval);
   313        var isVisible =
   314          element.getBoundingClientRect().left < window.innerWidth;
   315        app.ports.reportIsVisible.send([id, isVisible]);
   316      }
   317    }, 20);
   318  });
   319  
   320  app.ports.setFavicon.subscribe(function(url) {
   321    var oldIcon = document.getElementById("favicon");
   322    var newIcon = document.createElement("link");
   323    newIcon.id = "favicon";
   324    newIcon.rel = "shortcut icon";
   325    newIcon.href = url;
   326    if (oldIcon) {
   327      document.head.removeChild(oldIcon);
   328    }
   329  
   330    document.head.appendChild(newIcon);
   331  });
   332  
   333  app.ports.rawHttpRequest.subscribe(function(url) {
   334    var xhr = new XMLHttpRequest();
   335  
   336    xhr.addEventListener('error', function(error) {
   337      app.ports.rawHttpResponse.send('networkError');
   338    });
   339    xhr.addEventListener('timeout', function() {
   340      app.ports.rawHttpResponse.send('timeout');
   341    });
   342    xhr.addEventListener('load', function() {
   343      app.ports.rawHttpResponse.send('success');
   344    });
   345  
   346    xhr.open('GET', url, false);
   347  
   348    try {
   349      xhr.send();
   350      if (xhr.readyState === 1) {
   351        app.ports.rawHttpResponse.send('browserError');
   352      }
   353    } catch (error) {
   354      app.ports.rawHttpResponse.send('networkError');
   355    }
   356  });
   357  
   358  app.ports.renderSvgIcon.subscribe(function(icon, id) {
   359    renderingModulePromise.then(({addIcon}) => addIcon(icon, (typeof id !== 'undefined') ? id : icon));
   360  });
   361  
   362  var clipboard = new ClipboardJS('#copy-token');