M core/routes.go => core/routes.go +1 -0
@@ 1357,6 1357,7 @@ func (s *Service) OrgLinksList(c echo.Context) error {
pd.Data["include_tags"] = lt.Translate("Include Tags")
pd.Data["exclude_tags"] = lt.Translate("Exclude Tags")
pd.Data["apply"] = lt.Translate("Apply")
+ pd.Data["clear"] = lt.Translate("Clear")
orgLinks := result.OrgLinks.Result
gmap := gobwebs.Map{
"pd": pd,
M static/css/style.css => static/css/style.css +10 -0
@@ 427,6 427,16 @@ a.bullet-link:before {
border-radius: 4px;
}
+.autocomplete-tags {
+ padding: 10px;
+ z-index: 1000;
+ position: absolute;
+ background-color: #fff;
+ width: 250px;
+ border: 1px solid var(--color-lightGrey);
+ border-radius: 4px;
+}
+
.tag-suggested {
margin-bottom: 5px;
cursor: pointer;
A static/js/advancedsearch.js => static/js/advancedsearch.js +57 -0
@@ 0,0 1,57 @@
+var url = document.querySelector('body').getAttribute('data-autocomplete');
+var tagSelectors = document.querySelectorAll(".tag-selector");
+
+function autocomplete() {
+ tags = this.value.split(",")
+ tag = tags[tags.length -1].trim()
+
+ autocompleteTags = undefined;
+ if (this.nextElementSibling && this.nextElementSibling.classList.contains("autocomplete-tags")) {
+ autocompleteTags = this.nextElementSibling;
+ }
+ if (tag !== "") {
+ fetch(url + "?q=" + tag)
+ .then(function (response) {
+ if (!response.ok) {
+ console.log("Network response was not ok");
+ }
+ return response.json();
+ })
+ .then(function (data) {
+ if (data.length > 0) {
+ var t = "";
+ for (var i=0; i < data.length; i++) {
+ t += '<p class="tag-suggested">' + data[i].Name + '</p>';
+ }
+ if (autocompleteTags !== undefined) {
+ autocompleteTags.innerHTML = t;
+ autocompleteTags.classList.remove("d-none");
+ }
+ }
+ })
+ .catch(function (error) {
+ console.log("Fetch error:", error);
+ });
+ } else {
+ autocompleteTags.classList.add("d-none");
+ }
+
+ tagSelector = this;
+ autocompleteTags.addEventListener("click", function(event) {
+ if (event.target.classList.contains("tag-suggested")) {
+ newTag = event.target.textContent + ", ";
+ if (tags.length > 1) {
+ newTag = " " + newTag;
+ }
+ tags[tags.length - 1] = newTag;
+ tagSelector.value = tags.join(",");
+ autocompleteTags.classList.add("d-none");
+ tagSelector.focus();
+ }
+ });
+}
+
+tagSelectors.forEach(function(tagSelector) {
+ tagSelector.addEventListener('keyup', autocomplete);
+});
+
M templates/base.html => templates/base.html +4 -1
@@ 12,7 12,7 @@
<link rel="icon" type="image/png" sizes="16x16" href="{{ staticURL "img/favicon-16x16.png" }}?{{.serverVersion}}" />
<link rel="apple-touch-icon" type="image/png" href="{{ staticURL "img/apple-touch-icon.png" }}?{{.serverVersion}}" />
</head>
- <body class="container"{{if .useTagAutocomplete}} data-autocomplete="{{reverse "core:tag_autocomplete"}}"{{end}}>
+ <body class="container"{{if or .useTagAutocomplete .advancedSearch}} data-autocomplete="{{reverse "core:tag_autocomplete"}}"{{end}}>
<aside>
<div>
<h1>{{.base_pd.Title}}</h1>
@@ 217,5 217,8 @@
{{if .useTagAutocomplete}}
<script src="{{staticURL "js/autocomplete.js"}}?{{.serverVersion}}"></script>
{{end}}
+ {{if .advancedSearch}}
+ <script src="{{staticURL "js/advancedsearch.js"}}?{{.serverVersion}}"></script>
+ {{end}}
</html>
{{end}}
M templates/link_list.html => templates/link_list.html +7 -4
@@ 2,7 2,7 @@
<section class="app-header app-header-advanced-search">
<h1 class="app-header__title">{{ if .isOrgLink }}{{ .org.Name }} {{.pd.Title}}{{else if not .isPopular}}{{.pd.Data.recent}}{{else}}{{.pd.Data.popular}}{{end}}</h1>
<div>
- <form class="app-header__search app-header__search--stack" method="GET"
+ <form class="app-header__search app-header__search--stack" method="GET" id="advanced-search"
action="{{if .isPopular}}{{reverse "core:popular_link_list"}}{{else if .isOrgLink}}{{reverse "core:home_link_list"}}{{else}}{{reverse "core:recent_link_list"}}{{end}}">
<div class="app-header__search app-header__search--inline">
<input type="search" name="q" value="{{.search}}"/>
@@ 17,14 17,17 @@
<p><a href="#">{{.pd.Data.advanced_search}}</a></p>
<div>
<label>{{.pd.Data.include_tags}}</label>
- <input type="text" name="tag" value="{{.tagFilter}}"/>
+ <input type="text" name="tag" value="{{.tagFilter}}" class="tag-selector" autocomplete="off"/>
+ <div class="d-none autocomplete-tags">Include</div>
</div>
<div>
<label>{{.pd.Data.exclude_tags}}</label>
- <input type="text" name="exclude" value="{{.excludeTagFilter}}"/>
+ <input type="text" name="exclude" value="{{.excludeTagFilter}}" class="tag-selector" autocomplete="off"/>
+ <div class="d-none autocomplete-tags">Exclude</div>
</div>
<p class="mt-1 pull-right">
- <button type="submit" class="button primary small is-small">{{.pd.Data.apply}}</button>
+ <a href="#" class="button primary is-small">{{.pd.Data.clear}}</a>
+ <button type="submit" class="button primary is-small">{{.pd.Data.apply}}</button>
</p>
</div>
{{end}}