_table.html.erb 5.8 KB
Newer Older
1
<% content_for :style do %>
2
  #route_table {
3
    margin: 0;
4 5 6
    border-collapse: collapse;
  }

7 8 9 10 11 12
  #route_table thead tr {
    border-bottom: 2px solid #ddd;
  }

  #route_table thead tr.bottom {
    border-bottom: none;
13 14
  }

15 16
  #route_table thead tr.bottom th {
    padding: 10px 0;
17 18 19
    line-height: 15px;
  }

20 21 22 23
  #route_table thead tr.bottom th input#search {
    -webkit-appearance: textfield;
  }

24 25 26 27 28 29 30 31
  #route_table tbody tr {
    border-bottom: 1px solid #ddd;
  }

  #route_table tbody tr:nth-child(odd) {
    background: #f2f2f2;
  }

32 33
  #route_table tbody.exact_matches,
  #route_table tbody.fuzzy_matches {
34
    background-color: LightGoldenRodYellow;
35
    border-bottom: solid 2px SlateGrey;
36 37
  }

38 39
  #route_table tbody.exact_matches tr,
  #route_table tbody.fuzzy_matches tr {
40 41 42 43 44 45
    background: none;
    border-bottom: none;
  }

  #route_table td {
    padding: 4px 30px;
46 47 48 49 50 51
  }

  #path_search {
    width: 80%;
    font-size: inherit;
  }
52 53 54 55 56 57 58 59 60 61 62

  @media (prefers-color-scheme: dark) {
    #route_table tbody tr:nth-child(odd) {
      background: #333;
    }

    #route_table tbody.exact_matches,
    #route_table tbody.fuzzy_matches {
      color: #333;
    }
  }
63
<% end %>
S
schneems 已提交
64 65 66 67

<table id='route_table' class='route_table'>
  <thead>
    <tr>
68 69 70 71 72 73 74
      <th>Helper</th>
      <th>HTTP Verb</th>
      <th>Path</th>
      <th>Controller#Action</th>
    </tr>
    <tr class='bottom'>
      <th><%# Helper %>
S
schneems 已提交
75 76 77
        <%= link_to "Path", "#", 'data-route-helper' => '_path',
                    title: "Returns a relative path (without the http or domain)" %> /
        <%= link_to "Url", "#", 'data-route-helper' => '_url',
78
                    title: "Returns an absolute URL (with the http and domain)"   %>
79 80 81 82
      </th>
      <th><%# HTTP Verb %>
      </th>
      <th><%# Path %>
83
        <%= search_field(:path, nil, id: 'search', placeholder: "Path Match") %>
84 85
      </th>
      <th><%# Controller#action %>
S
schneems 已提交
86 87 88
      </th>
    </tr>
  </thead>
89 90 91
  <tbody class='exact_matches' id='exact_matches'>
  </tbody>
  <tbody class='fuzzy_matches' id='fuzzy_matches'>
92
  </tbody>
S
schneems 已提交
93 94 95 96 97 98
  <tbody>
    <%= yield %>
  </tbody>
</table>

<script type='text/javascript'>
G
Godfrey Chan 已提交
99
  // support forEach iterator on NodeList
100
  NodeList.prototype.forEach = Array.prototype.forEach;
S
schneems 已提交
101

102 103
  // Enables path search functionality
  function setupMatchPaths() {
104 105 106 107 108
    // Check if there are any matched results in a section
    function checkNoMatch(section, noMatchText) {
      if (section.children.length <= 1) {
        section.innerHTML += noMatchText;
      }
109
    }
S
schneems 已提交
110

111
    // get JSON from URL and invoke callback with result
112 113 114 115 116 117 118 119
    function getJSON(url, success) {
      var xhr = new XMLHttpRequest();
      xhr.open('GET', url);
      xhr.onload = function() {
        if (this.status == 200)
          success(JSON.parse(this.response));
      };
      xhr.send();
120
    }
121

122 123 124 125 126
    function delayedKeyup(input, callback) {
      var timeout;
      input.onkeyup = function(){
        if (timeout) clearTimeout(timeout);
        timeout = setTimeout(callback, 300);
127 128 129
      }
    }

130
    // remove params or fragments
131
    function sanitizePath(path) {
132
      return path.replace(/[#?].*/, '');
133
    }
134

135 136 137 138
    var pathElements = document.querySelectorAll('#route_table [data-route-path]'),
        searchElem   = document.querySelector('#search'),
        exactSection = document.querySelector('#exact_matches'),
        fuzzySection = document.querySelector('#fuzzy_matches');
139 140 141 142

    // Remove matches when no search value is present
    searchElem.onblur = function(e) {
      if (searchElem.value === "") {
143 144
        exactSection.innerHTML = "";
        fuzzySection.innerHTML = "";
145
      }
146 147 148
    }

    // On key press perform a search for matching paths
149 150 151 152
    delayedKeyup(searchElem, function() {
      var path = sanitizePath(searchElem.value),
          defaultExactMatch = '<tr><th colspan="4">Paths Matching (' + path +'):</th></tr>',
          defaultFuzzyMatch = '<tr><th colspan="4">Paths Containing (' + path +'):</th></tr>',
153 154
          noExactMatch      = '<tr><th colspan="4">No Exact Matches Found</th></tr>',
          noFuzzyMatch      = '<tr><th colspan="4">No Fuzzy Matches Found</th></tr>';
155

156 157
      if (!path)
        return searchElem.onblur();
158

159 160 161 162
      getJSON('/rails/info/routes?path=' + path, function(matches){
        // Clear out results section
        exactSection.innerHTML = defaultExactMatch;
        fuzzySection.innerHTML = defaultFuzzyMatch;
163

164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
        // Display exact matches and fuzzy matches
        pathElements.forEach(function(elem) {
          var elemPath = elem.getAttribute('data-route-path');

          if (matches['exact'].indexOf(elemPath) != -1)
            exactSection.appendChild(elem.parentNode.cloneNode(true));

          if (matches['fuzzy'].indexOf(elemPath) != -1)
            fuzzySection.appendChild(elem.parentNode.cloneNode(true));
        })

        // Display 'No Matches' message when no matches are found
        checkNoMatch(exactSection, noExactMatch);
        checkNoMatch(fuzzySection, noFuzzyMatch);
      })
    })
180 181 182 183
  }

  // Enables functionality to toggle between `_path` and `_url` helper suffixes
  function setupRouteToggleHelperLinks() {
184

185 186
    // Sets content for each element
    function setValOn(elems, val) {
187 188
      elems.forEach(function(elem) {
        elem.innerHTML = val;
189
      });
190
    }
191

192 193
    // Sets onClick event for each element
    function onClick(elems, func) {
194
      elems.forEach(function(elem) {
195 196
        elem.onclick = func;
      });
197
    }
198 199

    var toggleLinks = document.querySelectorAll('#route_table [data-route-helper]');
200

201 202 203 204 205 206
    onClick(toggleLinks, function(){
      var helperTxt   = this.getAttribute("data-route-helper"),
          helperElems = document.querySelectorAll('[data-route-name] span.helper');

      setValOn(helperElems, helperTxt);
    });
207 208 209
  }

  setupMatchPaths();
S
schneems 已提交
210
  setupRouteToggleHelperLinks();
211 212 213

  // Focus the search input after page has loaded
  document.getElementById('search').focus();
S
schneems 已提交
214
</script>