Rollup merge of #7279 - xFrednet:7172-adapt-website-to-new-format, r=flip1995
Adapting the lint list to Clippy's new metadata format This is close to the end of a long living project to rewrite the lint metadata collection for Clippy. Progress on this has been tracked in #7172. This PR adds one of the last missing puzzle pieces, the actual display of all the changes that have been done in the background. A preview can be seen here: [Clippy's lint list](https://xfrednet.github.io/rust-clippy/master/index.html) The styling has been discussed on [zulip](https://rust-lang.zulipchat.com/#narrow/stream/257328-clippy/topic/Styling.20feedback.20for.20Clippy's.20lint.20list/near/239601067) but is still open to suggestion. Side note: It has been fun working on the website where we don't have unit tests and everything is just tested by playing around. However, it's good that this chaos is contained into this one part of Clippy. 🐛 --- Closes: #1303 Closes: #4310 This actually closes fewer things than I thought it would... changelog: Reworked Clippy's [website](https://rust-lang.github.io/rust-clippy/master/index.html): changelog: * Added applicability information about lints changelog: * Added a link to jump to the specific lint implementation changelog: * Adapted some styling and improved loading time r? `@flip1995`
This commit is contained in:
commit
ce465995d8
2 changed files with 172 additions and 63 deletions
|
@ -114,6 +114,8 @@ const DEPRECATED_LINT_TYPE: [&str; 3] = ["clippy_lints", "deprecated_lints", "Cl
|
||||||
|
|
||||||
/// The index of the applicability name of `paths::APPLICABILITY_VALUES`
|
/// The index of the applicability name of `paths::APPLICABILITY_VALUES`
|
||||||
const APPLICABILITY_NAME_INDEX: usize = 2;
|
const APPLICABILITY_NAME_INDEX: usize = 2;
|
||||||
|
/// This applicability will be set for unresolved applicability values.
|
||||||
|
const APPLICABILITY_UNRESOLVED_STR: &str = "Unresolved";
|
||||||
|
|
||||||
declare_clippy_lint! {
|
declare_clippy_lint! {
|
||||||
/// **What it does:** Collects metadata about clippy lints for the website.
|
/// **What it does:** Collects metadata about clippy lints for the website.
|
||||||
|
@ -192,7 +194,7 @@ impl Drop for MetadataCollector {
|
||||||
let mut lints = std::mem::take(&mut self.lints).into_sorted_vec();
|
let mut lints = std::mem::take(&mut self.lints).into_sorted_vec();
|
||||||
lints
|
lints
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
.for_each(|x| x.applicability = applicability_info.remove(&x.id));
|
.for_each(|x| x.applicability = Some(applicability_info.remove(&x.id).unwrap_or_default()));
|
||||||
|
|
||||||
// Outputting
|
// Outputting
|
||||||
if Path::new(OUTPUT_FILE).exists() {
|
if Path::new(OUTPUT_FILE).exists() {
|
||||||
|
@ -208,7 +210,7 @@ struct LintMetadata {
|
||||||
id: String,
|
id: String,
|
||||||
id_span: SerializableSpan,
|
id_span: SerializableSpan,
|
||||||
group: String,
|
group: String,
|
||||||
level: &'static str,
|
level: String,
|
||||||
docs: String,
|
docs: String,
|
||||||
/// This field is only used in the output and will only be
|
/// This field is only used in the output and will only be
|
||||||
/// mapped shortly before the actual output.
|
/// mapped shortly before the actual output.
|
||||||
|
@ -221,7 +223,7 @@ impl LintMetadata {
|
||||||
id,
|
id,
|
||||||
id_span,
|
id_span,
|
||||||
group,
|
group,
|
||||||
level,
|
level: level.to_string(),
|
||||||
docs,
|
docs,
|
||||||
applicability: None,
|
applicability: None,
|
||||||
}
|
}
|
||||||
|
@ -269,14 +271,16 @@ impl Serialize for ApplicabilityInfo {
|
||||||
where
|
where
|
||||||
S: Serializer,
|
S: Serializer,
|
||||||
{
|
{
|
||||||
let index = self.applicability.unwrap_or_default();
|
|
||||||
|
|
||||||
let mut s = serializer.serialize_struct("ApplicabilityInfo", 2)?;
|
let mut s = serializer.serialize_struct("ApplicabilityInfo", 2)?;
|
||||||
s.serialize_field("is_multi_part_suggestion", &self.is_multi_part_suggestion)?;
|
s.serialize_field("is_multi_part_suggestion", &self.is_multi_part_suggestion)?;
|
||||||
|
if let Some(index) = self.applicability {
|
||||||
s.serialize_field(
|
s.serialize_field(
|
||||||
"applicability",
|
"applicability",
|
||||||
&paths::APPLICABILITY_VALUES[index][APPLICABILITY_NAME_INDEX],
|
&paths::APPLICABILITY_VALUES[index][APPLICABILITY_NAME_INDEX],
|
||||||
)?;
|
)?;
|
||||||
|
} else {
|
||||||
|
s.serialize_field("applicability", APPLICABILITY_UNRESOLVED_STR)?;
|
||||||
|
}
|
||||||
s.end()
|
s.end()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -486,6 +490,13 @@ fn extract_attr_docs_or_lint(cx: &LateContext<'_>, item: &Item<'_>) -> Option<St
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// Would result in `Hello world!\n=^.^=\n`
|
/// Would result in `Hello world!\n=^.^=\n`
|
||||||
|
///
|
||||||
|
/// ---
|
||||||
|
///
|
||||||
|
/// This function may modify the doc comment to ensure that the string can be displayed using a
|
||||||
|
/// markdown viewer in Clippy's lint list. The following modifications could be applied:
|
||||||
|
/// * Removal of leading space after a new line. (Important to display tables)
|
||||||
|
/// * Ensures that code blocks only contain language information
|
||||||
fn extract_attr_docs(cx: &LateContext<'_>, item: &Item<'_>) -> Option<String> {
|
fn extract_attr_docs(cx: &LateContext<'_>, item: &Item<'_>) -> Option<String> {
|
||||||
let attrs = cx.tcx.hir().attrs(item.hir_id());
|
let attrs = cx.tcx.hir().attrs(item.hir_id());
|
||||||
let mut lines = attrs.iter().filter_map(ast::Attribute::doc_str);
|
let mut lines = attrs.iter().filter_map(ast::Attribute::doc_str);
|
||||||
|
@ -510,8 +521,13 @@ fn extract_attr_docs(cx: &LateContext<'_>, item: &Item<'_>) -> Option<String> {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// This removes the leading space that the macro translation introduces
|
||||||
|
if let Some(stripped_doc) = line.strip_prefix(' ') {
|
||||||
|
docs.push_str(stripped_doc);
|
||||||
|
} else if !line.is_empty() {
|
||||||
docs.push_str(line);
|
docs.push_str(line);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
Some(docs)
|
Some(docs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,17 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
|
<!--
|
||||||
|
Welcome to a Clippy's lint list, at least the source code of it. If you are
|
||||||
|
interested in contributing to this website checkout `util/gh-pages/index.html`
|
||||||
|
inside the rust-clippy repository.
|
||||||
|
|
||||||
|
Otherwise, have a great day =^.^=
|
||||||
|
-->
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8"/>
|
<meta charset="UTF-8"/>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
||||||
|
|
||||||
<title>ALL the Clippy Lints</title>
|
<title>Clippy Lints</title>
|
||||||
|
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/css/bootstrap.min.css"/>
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/css/bootstrap.min.css"/>
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.5.0/styles/github.min.css"/>
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.5.0/styles/github.min.css"/>
|
||||||
|
@ -22,15 +29,95 @@
|
||||||
|
|
||||||
.panel-heading { cursor: pointer; }
|
.panel-heading { cursor: pointer; }
|
||||||
|
|
||||||
.panel-title { display: flex; }
|
.panel-title { display: flex; flex-wrap: wrap;}
|
||||||
.panel-title .label { display: inline-block; }
|
.panel-title .label { display: inline-block; }
|
||||||
|
|
||||||
.panel-title-name { flex: 1; }
|
.panel-title-name { flex: 1; min-width: 400px;}
|
||||||
.panel-title-name span { vertical-align: bottom; }
|
.panel-title-name span { vertical-align: bottom; }
|
||||||
|
|
||||||
.panel .panel-title-name .anchor { display: none; }
|
.panel .panel-title-name .anchor { display: none; }
|
||||||
.panel:hover .panel-title-name .anchor { display: inline;}
|
.panel:hover .panel-title-name .anchor { display: inline;}
|
||||||
|
|
||||||
|
.label {
|
||||||
|
padding-top: 0.3em;
|
||||||
|
padding-bottom: 0.3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label-lint-group {
|
||||||
|
min-width: 8em;
|
||||||
|
}
|
||||||
|
.label-lint-level {
|
||||||
|
min-width: 4em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label-lint-level-allow {
|
||||||
|
background-color: #5cb85c;
|
||||||
|
}
|
||||||
|
.label-lint-level-warn {
|
||||||
|
background-color: #f0ad4e;
|
||||||
|
}
|
||||||
|
.label-lint-level-deny {
|
||||||
|
background-color: #d9534f;
|
||||||
|
}
|
||||||
|
.label-lint-level-none {
|
||||||
|
background-color: #777777;
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label-group-deprecated {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label-doc-folding {
|
||||||
|
color: #000;
|
||||||
|
background-color: #fff;
|
||||||
|
border: 1px solid var(--theme-popup-border);
|
||||||
|
}
|
||||||
|
.label-doc-folding:hover {
|
||||||
|
background-color: #e6e6e6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lint-doc-md > h3 {
|
||||||
|
border-top: 1px solid var(--theme-popup-border);
|
||||||
|
padding: 10px 15px;
|
||||||
|
margin: 0 -15px;
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
.lint-doc-md > h3:first-child {
|
||||||
|
border-top: none;
|
||||||
|
padding-top: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width:749px) {
|
||||||
|
.lint-additional-info-container {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: column;
|
||||||
|
}
|
||||||
|
.lint-additional-info-item + .lint-additional-info-item {
|
||||||
|
border-top: 1px solid var(--theme-popup-border);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media (min-width:750px) {
|
||||||
|
.lint-additional-info-container {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: row;
|
||||||
|
}
|
||||||
|
.lint-additional-info-item + .lint-additional-info-item {
|
||||||
|
border-left: 1px solid var(--theme-popup-border);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.lint-additional-info-item {
|
||||||
|
display: inline-flex;
|
||||||
|
min-width: 200px;
|
||||||
|
flex-grow: 1;
|
||||||
|
padding: 9px 5px 5px 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label-applicability {
|
||||||
|
background-color: #777777;
|
||||||
|
margin: auto 5px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
<style>
|
<style>
|
||||||
/* Expanding the mdBoom theme*/
|
/* Expanding the mdBoom theme*/
|
||||||
|
@ -159,7 +246,7 @@
|
||||||
|
|
||||||
<div class="container" ng-app="clippy" ng-controller="lintList">
|
<div class="container" ng-app="clippy" ng-controller="lintList">
|
||||||
<div class="page-header">
|
<div class="page-header">
|
||||||
<h1>ALL the Clippy Lints</h1>
|
<h1>Clippy Lints</h1>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<noscript>
|
<noscript>
|
||||||
|
@ -181,9 +268,12 @@
|
||||||
<div class="panel-body row filter-panel">
|
<div class="panel-body row filter-panel">
|
||||||
<div class="col-md-6 form-inline">
|
<div class="col-md-6 form-inline">
|
||||||
<div class="form-group form-group-lg">
|
<div class="form-group form-group-lg">
|
||||||
<p class="h4">Lint levels</p>
|
<p class="h4">
|
||||||
|
Lint levels
|
||||||
|
<a href="https://doc.rust-lang.org/rustc/lints/levels.html">(?)</a>
|
||||||
|
</p>
|
||||||
<div class="checkbox" ng-repeat="(level, enabled) in levels">
|
<div class="checkbox" ng-repeat="(level, enabled) in levels">
|
||||||
<label>
|
<label class="text-capitalize">
|
||||||
<input type="checkbox" ng-model="levels[level]" />
|
<input type="checkbox" ng-model="levels[level]" />
|
||||||
{{level}}
|
{{level}}
|
||||||
</label>
|
</label>
|
||||||
|
@ -192,7 +282,10 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6 form-inline">
|
<div class="col-md-6 form-inline">
|
||||||
<div class="form-group form-group-lg">
|
<div class="form-group form-group-lg">
|
||||||
<p class="h4">Lint groups</p>
|
<p class="h4">
|
||||||
|
Lint groups
|
||||||
|
<a href="https://github.com/rust-lang/rust-clippy/#clippy">(?)</a>
|
||||||
|
</p>
|
||||||
<div class="checkbox" ng-repeat="(group, enabled) in groups">
|
<div class="checkbox" ng-repeat="(group, enabled) in groups">
|
||||||
<label class="text-capitalize">
|
<label class="text-capitalize">
|
||||||
<input type="checkbox" ng-model="groups[group]" />
|
<input type="checkbox" ng-model="groups[group]" />
|
||||||
|
@ -216,9 +309,8 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- The order of the filters should be from most likely to remove a lint to least likely to improve performance. -->
|
||||||
<article class="panel panel-default" id="{{lint.id}}"
|
<article class="panel panel-default" id="{{lint.id}}" ng-repeat="lint in data | filter:bySearch | filter:byGroups | filter:byLevels">
|
||||||
ng-repeat="lint in data | filter:byLevels | filter:byGroups | filter:bySearch | orderBy:'id' track by lint.id">
|
|
||||||
<header class="panel-heading" ng-click="open[lint.id] = !open[lint.id]">
|
<header class="panel-heading" ng-click="open[lint.id] = !open[lint.id]">
|
||||||
<h2 class="panel-title">
|
<h2 class="panel-title">
|
||||||
<div class="panel-title-name">
|
<div class="panel-title-name">
|
||||||
|
@ -227,29 +319,36 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="panel-title-addons">
|
<div class="panel-title-addons">
|
||||||
<span class="label label-default text-capitalize">{{lint.group}}</span>
|
<span class="label label-lint-group label-default label-group-{{lint.group}}">{{lint.group}}</span>
|
||||||
|
|
||||||
<span ng-if="lint.level == 'Allow'" class="label label-success">Allow</span>
|
<span class="label label-lint-level label-lint-level-{{lint.level}}">{{lint.level}}</span>
|
||||||
<span ng-if="lint.level == 'Warn'" class="label label-warning">Warn</span>
|
|
||||||
<span ng-if="lint.level == 'Deny'" class="label label-danger">Deny</span>
|
|
||||||
<span ng-if="lint.level == 'Deprecated'" class="label label-default">Deprecated</span>
|
|
||||||
|
|
||||||
<button class="btn btn-default btn-xs">
|
|
||||||
<span ng-show="open[lint.id]">−</span>
|
<span class="label label-doc-folding" ng-show="open[lint.id]">−</span>
|
||||||
<span ng-hide="open[lint.id]">+</span>
|
<span class="label label-doc-folding" ng-hide="open[lint.id]">+</span>
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</h2>
|
</h2>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<ul class="list-group lint-docs" ng-if="lint.docs" ng-class="{collapse: true, in: open[lint.id]}">
|
<ul class="list-group lint-docs" ng-class="{collapse: true, in: open[lint.id]}">
|
||||||
<li class="list-group-item" ng-repeat="(title, text) in lint.docs">
|
<div class="list-group-item lint-doc-md" ng-bind-html="lint.docs | markdown"></div>
|
||||||
<h4 class="list-group-item-heading">
|
<div class="lint-additional-info-container">
|
||||||
{{title}}
|
<!-- Applicability -->
|
||||||
</h4>
|
<div class="lint-additional-info-item">
|
||||||
<div class="list-group-item-text" ng-bind-html="text | markdown"></div>
|
<span> Applicability: </span>
|
||||||
<a ng-if="title == 'Known problems'" href="https://github.com/rust-lang/rust-clippy/issues?q=is%3Aissue+is%3Aopen+{{lint.id}}">Search on GitHub</a>
|
<span class="label label-default label-applicability">{{lint.applicability.applicability}}</span>
|
||||||
</li>
|
<a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint_defs/enum.Applicability.html#variants">(?)</a>
|
||||||
|
</div>
|
||||||
|
<!-- TODO xFrednet 2021-05-19: Somehow collect and show the version See rust-clippy#6492 -->
|
||||||
|
<!-- Open related issues -->
|
||||||
|
<div class="lint-additional-info-item">
|
||||||
|
<a href="https://github.com/rust-lang/rust-clippy/issues?q=is%3Aissue+{{lint.id}}">Related Issues</a>
|
||||||
|
</div>
|
||||||
|
<!-- Jump to source -->
|
||||||
|
<div class="lint-additional-info-item">
|
||||||
|
<a href="https://github.com/rust-lang/rust-clippy/blob/{{docVersion}}/clippy_lints/{{lint.id_span.path}}#L{{lint.id_span.line}}">View Source</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</ul>
|
</ul>
|
||||||
</article>
|
</article>
|
||||||
</div>
|
</div>
|
||||||
|
@ -310,22 +409,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function searchLint(lint, term) {
|
|
||||||
for (const field in lint.docs) {
|
|
||||||
// Continue if it's not a property
|
|
||||||
if (!lint.docs.hasOwnProperty(field)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return if not found
|
|
||||||
if (lint.docs[field].toLowerCase().indexOf(term) !== -1) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
angular.module("clippy", [])
|
angular.module("clippy", [])
|
||||||
.filter('markdown', function ($sce) {
|
.filter('markdown', function ($sce) {
|
||||||
return function (text) {
|
return function (text) {
|
||||||
|
@ -350,13 +433,25 @@
|
||||||
})
|
})
|
||||||
.controller("lintList", function ($scope, $http, $timeout) {
|
.controller("lintList", function ($scope, $http, $timeout) {
|
||||||
// Level filter
|
// Level filter
|
||||||
var LEVEL_FILTERS_DEFAULT = {Allow: true, Warn: true, Deny: true, Deprecated: true};
|
var LEVEL_FILTERS_DEFAULT = {allow: true, warn: true, deny: true, none: true};
|
||||||
$scope.levels = LEVEL_FILTERS_DEFAULT;
|
$scope.levels = LEVEL_FILTERS_DEFAULT;
|
||||||
$scope.byLevels = function (lint) {
|
$scope.byLevels = function (lint) {
|
||||||
return $scope.levels[lint.level];
|
return $scope.levels[lint.level];
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.groups = {};
|
var GROUPS_FILTER_DEFAULT = {
|
||||||
|
cargo: true,
|
||||||
|
complexity: true,
|
||||||
|
correctness: true,
|
||||||
|
deprecated: false,
|
||||||
|
nursery: true,
|
||||||
|
pedantic: true,
|
||||||
|
perf: true,
|
||||||
|
restriction: true,
|
||||||
|
style: true,
|
||||||
|
suspicious: true,
|
||||||
|
};
|
||||||
|
$scope.groups = GROUPS_FILTER_DEFAULT;
|
||||||
$scope.byGroups = function (lint) {
|
$scope.byGroups = function (lint) {
|
||||||
return $scope.groups[lint.group];
|
return $scope.groups[lint.group];
|
||||||
};
|
};
|
||||||
|
@ -377,12 +472,14 @@
|
||||||
// Search the description
|
// Search the description
|
||||||
// The use of `for`-loops instead of `foreach` enables us to return early
|
// The use of `for`-loops instead of `foreach` enables us to return early
|
||||||
let terms = searchStr.split(" ");
|
let terms = searchStr.split(" ");
|
||||||
|
let docsLowerCase = lint.docs.toLowerCase();
|
||||||
for (index = 0; index < terms.length; index++) {
|
for (index = 0; index < terms.length; index++) {
|
||||||
if (lint.id.indexOf(terms[index]) !== -1) {
|
// This is more likely and will therefor be checked first
|
||||||
|
if (docsLowerCase.indexOf(terms[index]) !== -1) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (searchLint(lint, terms[index])) {
|
if (lint.id.indexOf(terms[index]) !== -1) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -395,6 +492,8 @@
|
||||||
// Get data
|
// Get data
|
||||||
$scope.open = {};
|
$scope.open = {};
|
||||||
$scope.loading = true;
|
$scope.loading = true;
|
||||||
|
// This will be used to jump into the source code of the version that this documentation is for.
|
||||||
|
$scope.docVersion = window.location.pathname.split('/')[2] || "master";
|
||||||
|
|
||||||
if (window.location.hash.length > 1) {
|
if (window.location.hash.length > 1) {
|
||||||
$scope.search = window.location.hash.slice(1);
|
$scope.search = window.location.hash.slice(1);
|
||||||
|
@ -407,12 +506,6 @@
|
||||||
$scope.data = data;
|
$scope.data = data;
|
||||||
$scope.loading = false;
|
$scope.loading = false;
|
||||||
|
|
||||||
// Initialize lint groups (the same structure is also used to enable filtering)
|
|
||||||
$scope.groups = data.reduce(function (result, val) {
|
|
||||||
result[val.group] = true;
|
|
||||||
return result;
|
|
||||||
}, {});
|
|
||||||
|
|
||||||
var selectedGroup = getQueryVariable("sel");
|
var selectedGroup = getQueryVariable("sel");
|
||||||
if (selectedGroup) {
|
if (selectedGroup) {
|
||||||
selectGroup($scope, selectedGroup.toLowerCase());
|
selectGroup($scope, selectedGroup.toLowerCase());
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue