|
24 | 24 | target.scrollIntoView();
|
25 | 25 | }
|
26 | 26 |
|
27 |
| - function scrollToLintByURL($scope) { |
28 |
| - var removeListener = $scope.$on('ngRepeatFinished', function(ngRepeatFinishedEvent) { |
29 |
| - scrollToLint(window.location.hash.slice(1)); |
| 27 | + function scrollToLintByURL($scope, $location) { |
| 28 | + var removeListener = $scope.$on('ngRepeatFinished', function (ngRepeatFinishedEvent) { |
| 29 | + scrollToLint($location.path().substring(1)); |
30 | 30 | removeListener();
|
31 | 31 | });
|
32 | 32 | }
|
|
106 | 106 | }
|
107 | 107 | };
|
108 | 108 | })
|
109 |
| - .controller("lintList", function ($scope, $http, $timeout) { |
| 109 | + .controller("lintList", function ($scope, $http, $location) { |
110 | 110 | // Level filter
|
111 | 111 | var LEVEL_FILTERS_DEFAULT = {allow: true, warn: true, deny: true, none: true};
|
112 |
| - $scope.levels = LEVEL_FILTERS_DEFAULT; |
| 112 | + $scope.levels = { ...LEVEL_FILTERS_DEFAULT }; |
113 | 113 | $scope.byLevels = function (lint) {
|
114 | 114 | return $scope.levels[lint.level];
|
115 | 115 | };
|
|
146 | 146 | "=": {enabled: false, minorVersion: null },
|
147 | 147 | };
|
148 | 148 |
|
| 149 | + // Map the versionFilters to the query parameters in a way that is easier to work with in a URL |
| 150 | + const versionFilterKeyMap = { |
| 151 | + "≥": "gte", |
| 152 | + "≤": "lte", |
| 153 | + "=": "eq" |
| 154 | + }; |
| 155 | + const reverseVersionFilterKeyMap = Object.fromEntries( |
| 156 | + Object.entries(versionFilterKeyMap).map(([key, value]) => [value, key]) |
| 157 | + ); |
| 158 | + |
| 159 | + // loadFromURLParameters retrieves filter settings from the URL parameters and assigns them |
| 160 | + // to corresponding $scope variables. |
| 161 | + function loadFromURLParameters() { |
| 162 | + // Extract parameters from URL |
| 163 | + const urlParameters = $location.search(); |
| 164 | + |
| 165 | + // Define a helper function that assigns URL parameters to a provided scope variable |
| 166 | + const handleParameter = (parameter, scopeVariable) => { |
| 167 | + if (urlParameters[parameter]) { |
| 168 | + const items = urlParameters[parameter].split(','); |
| 169 | + for (const key in scopeVariable) { |
| 170 | + if (scopeVariable.hasOwnProperty(key)) { |
| 171 | + scopeVariable[key] = items.includes(key); |
| 172 | + } |
| 173 | + } |
| 174 | + } |
| 175 | + }; |
| 176 | + |
| 177 | + handleParameter('levels', $scope.levels); |
| 178 | + handleParameter('groups', $scope.groups); |
| 179 | + |
| 180 | + // Handle 'versions' parameter separately because it needs additional processing |
| 181 | + if (urlParameters.versions) { |
| 182 | + const versionFilters = urlParameters.versions.split(','); |
| 183 | + for (const versionFilter of versionFilters) { |
| 184 | + const [key, minorVersion] = versionFilter.split(':'); |
| 185 | + const parsedMinorVersion = parseInt(minorVersion); |
| 186 | + |
| 187 | + // Map the key from the URL parameter to its original form |
| 188 | + const originalKey = reverseVersionFilterKeyMap[key]; |
| 189 | + |
| 190 | + if (originalKey in $scope.versionFilters && !isNaN(parsedMinorVersion)) { |
| 191 | + $scope.versionFilters[originalKey].enabled = true; |
| 192 | + $scope.versionFilters[originalKey].minorVersion = parsedMinorVersion; |
| 193 | + } |
| 194 | + } |
| 195 | + } |
| 196 | + |
| 197 | + // Load the search parameter from the URL path |
| 198 | + const searchParameter = $location.path().substring(1); // Remove the leading slash |
| 199 | + if (searchParameter) { |
| 200 | + $scope.search = searchParameter; |
| 201 | + $scope.open[searchParameter] = true; |
| 202 | + scrollToLintByURL($scope, $location); |
| 203 | + } |
| 204 | + |
| 205 | + // If there are any filters in the URL, mark that the filters have been changed |
| 206 | + if (urlParameters.levels || urlParameters.groups || urlParameters.versions) { |
| 207 | + $scope.filtersChanged = true; |
| 208 | + } |
| 209 | + } |
| 210 | + |
| 211 | + // updateURLParameter updates the URL parameter with the given key to the given value |
| 212 | + function updateURLParameter(filterObj, urlKey, processFilter = filter => filter) { |
| 213 | + const parameter = Object.keys(filterObj) |
| 214 | + .filter(filter => filterObj[filter]) |
| 215 | + .map(processFilter) |
| 216 | + .filter(Boolean) // Filters out any falsy values, including null |
| 217 | + .join(','); |
| 218 | + |
| 219 | + $location.search(urlKey, parameter || null); |
| 220 | + } |
| 221 | + |
| 222 | + // updateVersionURLParameter updates the version URL parameter with the given version filters |
| 223 | + function updateVersionURLParameter(versionFilters) { |
| 224 | + updateURLParameter( |
| 225 | + versionFilters, |
| 226 | + 'versions', |
| 227 | + versionFilter => versionFilters[versionFilter].enabled && versionFilters[versionFilter].minorVersion != null |
| 228 | + ? `${versionFilterKeyMap[versionFilter]}:${versionFilters[versionFilter].minorVersion}` |
| 229 | + : null |
| 230 | + ); |
| 231 | + } |
| 232 | + |
| 233 | + // updateAllURLParameters updates all the URL parameters with the current filter settings |
| 234 | + function updateAllURLParameters() { |
| 235 | + updateURLParameter($scope.levels, 'levels'); |
| 236 | + updateURLParameter($scope.groups, 'groups'); |
| 237 | + updateVersionURLParameter($scope.versionFilters); |
| 238 | + } |
| 239 | + |
| 240 | + // Add $watches to automatically update URL parameters when the data changes |
| 241 | + $scope.$watch('levels', function (newVal, oldVal) { |
| 242 | + if (newVal !== oldVal) { |
| 243 | + $scope.filtersChanged = true; |
| 244 | + updateURLParameter(newVal, 'levels'); |
| 245 | + } |
| 246 | + }, true); |
| 247 | + |
| 248 | + $scope.$watch('groups', function (newVal, oldVal) { |
| 249 | + if (newVal !== oldVal) { |
| 250 | + $scope.filtersChanged = true; |
| 251 | + updateURLParameter(newVal, 'groups'); |
| 252 | + } |
| 253 | + }, true); |
| 254 | + |
| 255 | + $scope.$watch('versionFilters', function (newVal, oldVal) { |
| 256 | + if (newVal !== oldVal) { |
| 257 | + $scope.filtersChanged = true; |
| 258 | + updateVersionURLParameter(newVal); |
| 259 | + } |
| 260 | + }, true); |
| 261 | + |
| 262 | + $scope.$watch('search', function (newVal, oldVal) { |
| 263 | + if (newVal !== oldVal) { |
| 264 | + $location.path(newVal); |
| 265 | + } |
| 266 | + }); |
| 267 | + |
| 268 | + // Watch for changes in the URL path and update the search and lint display |
| 269 | + $scope.$watch(function () { |
| 270 | + return $location.path(); |
| 271 | + }, function (newPath) { |
| 272 | + const searchParameter = newPath.substring(1); |
| 273 | + if ($scope.search !== searchParameter) { |
| 274 | + $scope.search = searchParameter; |
| 275 | + $scope.open[searchParameter] = true; |
| 276 | + scrollToLintByURL($scope, $location); |
| 277 | + } |
| 278 | + }); |
| 279 | + |
149 | 280 | $scope.selectTheme = function (theme) {
|
150 | 281 | setTheme(theme, true);
|
151 | 282 | }
|
|
272 | 403 | return true;
|
273 | 404 | }
|
274 | 405 |
|
| 406 | + // Show details for one lint |
| 407 | + $scope.openLint = function (lint) { |
| 408 | + $scope.open[lint.id] = true; |
| 409 | + $location.path(lint.id); |
| 410 | + if ($scope.filtersChanged) { |
| 411 | + updateAllURLParameters(); |
| 412 | + $scope.filtersChanged = false; |
| 413 | + } |
| 414 | + }; |
| 415 | + |
275 | 416 | $scope.copyToClipboard = function (lint) {
|
276 | 417 | const clipboard = document.getElementById("clipboard-" + lint.id);
|
277 | 418 | if (clipboard) {
|
|
296 | 437 | // Get data
|
297 | 438 | $scope.open = {};
|
298 | 439 | $scope.loading = true;
|
| 440 | + $scope.filtersChanged = false; |
| 441 | + |
299 | 442 | // This will be used to jump into the source code of the version that this documentation is for.
|
300 | 443 | $scope.docVersion = window.location.pathname.split('/')[2] || "master";
|
301 | 444 |
|
302 |
| - if (window.location.hash.length > 1) { |
303 |
| - $scope.search = window.location.hash.slice(1); |
304 |
| - $scope.open[window.location.hash.slice(1)] = true; |
305 |
| - scrollToLintByURL($scope); |
306 |
| - } |
| 445 | + // Set up the filters from the URL parameters before we start loading the data |
| 446 | + loadFromURLParameters(); |
307 | 447 |
|
308 | 448 | $http.get('./lints.json')
|
309 | 449 | .success(function (data) {
|
|
315 | 455 | selectGroup($scope, selectedGroup.toLowerCase());
|
316 | 456 | }
|
317 | 457 |
|
318 |
| - scrollToLintByURL($scope); |
| 458 | + scrollToLintByURL($scope, $location); |
319 | 459 |
|
320 | 460 | setTimeout(function () {
|
321 | 461 | var el = document.getElementById('filter-input');
|
|
326 | 466 | $scope.error = data;
|
327 | 467 | $scope.loading = false;
|
328 | 468 | });
|
329 |
| - |
330 |
| - window.addEventListener('hashchange', function () { |
331 |
| - // trigger re-render |
332 |
| - $timeout(function () { |
333 |
| - $scope.levels = LEVEL_FILTERS_DEFAULT; |
334 |
| - $scope.search = window.location.hash.slice(1); |
335 |
| - $scope.open[window.location.hash.slice(1)] = true; |
336 |
| - |
337 |
| - scrollToLintByURL($scope); |
338 |
| - }); |
339 |
| - return true; |
340 |
| - }, false); |
341 | 469 | });
|
342 | 470 | })();
|
343 | 471 |
|
|
0 commit comments