|
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, $timeout) { |
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, defaultValues) => { |
| 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 | + } else if (defaultValues) { |
| 175 | + for (const key in defaultValues) { |
| 176 | + if (scopeVariable.hasOwnProperty(key)) { |
| 177 | + scopeVariable[key] = defaultValues[key]; |
| 178 | + } |
| 179 | + } |
| 180 | + } |
| 181 | + }; |
| 182 | + |
| 183 | + handleParameter('levels', $scope.levels, LEVEL_FILTERS_DEFAULT); |
| 184 | + handleParameter('groups', $scope.groups, GROUPS_FILTER_DEFAULT); |
| 185 | + |
| 186 | + // Handle 'versions' parameter separately because it needs additional processing |
| 187 | + if (urlParameters.versions) { |
| 188 | + const versionFilters = urlParameters.versions.split(','); |
| 189 | + for (const versionFilter of versionFilters) { |
| 190 | + const [key, minorVersion] = versionFilter.split(':'); |
| 191 | + const parsedMinorVersion = parseInt(minorVersion); |
| 192 | + |
| 193 | + // Map the key from the URL parameter to its original form |
| 194 | + const originalKey = reverseVersionFilterKeyMap[key]; |
| 195 | + |
| 196 | + if (originalKey in $scope.versionFilters && !isNaN(parsedMinorVersion)) { |
| 197 | + $scope.versionFilters[originalKey].enabled = true; |
| 198 | + $scope.versionFilters[originalKey].minorVersion = parsedMinorVersion; |
| 199 | + } |
| 200 | + } |
| 201 | + } |
| 202 | + |
| 203 | + // Load the search parameter from the URL path |
| 204 | + const searchParameter = $location.path().substring(1); // Remove the leading slash |
| 205 | + if (searchParameter) { |
| 206 | + $scope.search = searchParameter; |
| 207 | + $scope.open[searchParameter] = true; |
| 208 | + scrollToLintByURL($scope, $location); |
| 209 | + } |
| 210 | + } |
| 211 | + |
| 212 | + // updateURLParameter updates the URL parameter with the given key to the given value |
| 213 | + function updateURLParameter(filterObj, urlKey, defaultValue = {}, processFilter = filter => filter) { |
| 214 | + const parameter = Object.keys(filterObj) |
| 215 | + .filter(filter => filterObj[filter]) |
| 216 | + .sort() |
| 217 | + .map(processFilter) |
| 218 | + .filter(Boolean) // Filters out any falsy values, including null |
| 219 | + .join(','); |
| 220 | + |
| 221 | + const defaultParameter = Object.keys(defaultValue) |
| 222 | + .filter(filter => defaultValue[filter]) |
| 223 | + .sort() |
| 224 | + .map(processFilter) |
| 225 | + .filter(Boolean) // Filters out any falsy values, including null |
| 226 | + .join(','); |
| 227 | + |
| 228 | + // if we ended up back at the defaults, just remove it from the URL |
| 229 | + if (parameter === defaultParameter) { |
| 230 | + $location.search(urlKey, null); |
| 231 | + } else { |
| 232 | + $location.search(urlKey, parameter || null); |
| 233 | + } |
| 234 | + } |
| 235 | + |
| 236 | + // updateVersionURLParameter updates the version URL parameter with the given version filters |
| 237 | + function updateVersionURLParameter(versionFilters) { |
| 238 | + updateURLParameter( |
| 239 | + versionFilters, |
| 240 | + 'versions', {}, |
| 241 | + versionFilter => versionFilters[versionFilter].enabled && versionFilters[versionFilter].minorVersion != null |
| 242 | + ? `${versionFilterKeyMap[versionFilter]}:${versionFilters[versionFilter].minorVersion}` |
| 243 | + : null |
| 244 | + ); |
| 245 | + } |
| 246 | + |
| 247 | + // updateAllURLParameters updates all the URL parameters with the current filter settings |
| 248 | + function updateAllURLParameters() { |
| 249 | + updateURLParameter($scope.levels, 'levels', LEVEL_FILTERS_DEFAULT); |
| 250 | + updateURLParameter($scope.groups, 'groups', GROUPS_FILTER_DEFAULT); |
| 251 | + updateVersionURLParameter($scope.versionFilters); |
| 252 | + } |
| 253 | + |
| 254 | + // Add $watches to automatically update URL parameters when the data changes |
| 255 | + $scope.$watch('levels', function (newVal, oldVal) { |
| 256 | + if (newVal !== oldVal) { |
| 257 | + updateURLParameter(newVal, 'levels', LEVEL_FILTERS_DEFAULT); |
| 258 | + } |
| 259 | + }, true); |
| 260 | + |
| 261 | + $scope.$watch('groups', function (newVal, oldVal) { |
| 262 | + if (newVal !== oldVal) { |
| 263 | + updateURLParameter(newVal, 'groups', GROUPS_FILTER_DEFAULT); |
| 264 | + } |
| 265 | + }, true); |
| 266 | + |
| 267 | + $scope.$watch('versionFilters', function (newVal, oldVal) { |
| 268 | + if (newVal !== oldVal) { |
| 269 | + updateVersionURLParameter(newVal); |
| 270 | + } |
| 271 | + }, true); |
| 272 | + |
| 273 | + // Watch for changes in the URL path and update the search and lint display |
| 274 | + $scope.$watch(function () { return $location.path(); }, function (newPath) { |
| 275 | + const searchParameter = newPath.substring(1); |
| 276 | + if ($scope.search !== searchParameter) { |
| 277 | + $scope.search = searchParameter; |
| 278 | + $scope.open[searchParameter] = true; |
| 279 | + scrollToLintByURL($scope, $location); |
| 280 | + } |
| 281 | + }); |
| 282 | + |
| 283 | + let debounceTimeout; |
| 284 | + $scope.$watch('search', function (newVal, oldVal) { |
| 285 | + if (newVal !== oldVal) { |
| 286 | + if (debounceTimeout) { |
| 287 | + $timeout.cancel(debounceTimeout); |
| 288 | + } |
| 289 | + |
| 290 | + debounceTimeout = $timeout(function () { |
| 291 | + $location.path(newVal); |
| 292 | + }, 1000); |
| 293 | + } |
| 294 | + }); |
| 295 | + |
| 296 | + $scope.$watch(function () { return $location.search(); }, function (newParameters) { |
| 297 | + loadFromURLParameters(); |
| 298 | + }, true); |
| 299 | + |
| 300 | + $scope.updatePath = function () { |
| 301 | + if (debounceTimeout) { |
| 302 | + $timeout.cancel(debounceTimeout); |
| 303 | + } |
| 304 | + |
| 305 | + $location.path($scope.search); |
| 306 | + } |
| 307 | + |
149 | 308 | $scope.selectTheme = function (theme) {
|
150 | 309 | setTheme(theme, true);
|
151 | 310 | }
|
|
169 | 328 | };
|
170 | 329 |
|
171 | 330 | $scope.resetGroupsToDefault = function () {
|
172 |
| - const groups = $scope.groups; |
173 |
| - for (const [key, value] of Object.entries(GROUPS_FILTER_DEFAULT)) { |
174 |
| - groups[key] = value; |
175 |
| - } |
| 331 | + $scope.groups = { |
| 332 | + ...GROUPS_FILTER_DEFAULT |
| 333 | + }; |
176 | 334 | };
|
177 | 335 |
|
178 | 336 | $scope.selectedValuesCount = function (obj) {
|
|
272 | 430 | return true;
|
273 | 431 | }
|
274 | 432 |
|
| 433 | + // Show details for one lint |
| 434 | + $scope.openLint = function (lint) { |
| 435 | + $scope.open[lint.id] = true; |
| 436 | + $location.path(lint.id); |
| 437 | + }; |
| 438 | + |
275 | 439 | $scope.copyToClipboard = function (lint) {
|
276 | 440 | const clipboard = document.getElementById("clipboard-" + lint.id);
|
277 | 441 | if (clipboard) {
|
|
296 | 460 | // Get data
|
297 | 461 | $scope.open = {};
|
298 | 462 | $scope.loading = true;
|
| 463 | + |
299 | 464 | // This will be used to jump into the source code of the version that this documentation is for.
|
300 | 465 | $scope.docVersion = window.location.pathname.split('/')[2] || "master";
|
301 | 466 |
|
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 |
| - } |
| 467 | + // Set up the filters from the URL parameters before we start loading the data |
| 468 | + loadFromURLParameters(); |
307 | 469 |
|
308 | 470 | $http.get('./lints.json')
|
309 | 471 | .success(function (data) {
|
|
315 | 477 | selectGroup($scope, selectedGroup.toLowerCase());
|
316 | 478 | }
|
317 | 479 |
|
318 |
| - scrollToLintByURL($scope); |
| 480 | + scrollToLintByURL($scope, $location); |
319 | 481 |
|
320 | 482 | setTimeout(function () {
|
321 | 483 | var el = document.getElementById('filter-input');
|
|
326 | 488 | $scope.error = data;
|
327 | 489 | $scope.loading = false;
|
328 | 490 | });
|
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 | 491 | });
|
342 | 492 | })();
|
343 | 493 |
|
|
0 commit comments