diff --git a/css/site-search.css b/css/site-search.css new file mode 100644 index 00000000..7bb3a3ea --- /dev/null +++ b/css/site-search.css @@ -0,0 +1,107 @@ +.search-button { + width: 28px; + height: 100%; + border: 1px solid #4e7963; + background: #4e7963; + text-align: center; + color: #fff; + border-radius: 0 5px 5px 0; + cursor: pointer; + margin: 0 !important; + position: relative; + left: -4px; +} +.search-input { + padding: 5px; +} +.search-bar { + display: flex; +} +.search-bar-home { + padding: 1ex 0.5em; + width: 20em; + font-size: 1.3rem; + line-height: 1; + background: #fff; + border: 1px solid #d5d5d5; + border-radius: 2px; + box-shadow: inset 0 5px 5px -5px rgba(0, 0, 0, 0.2); + box-sizing: border-box; +} +.autocomplete { + /*the container must be positioned relative:*/ + position: relative; +} +.search-example-2 { + position: relative; + left: 0; + width: 20em; +} +.autocomplete-items { + position: absolute; + border: 1px solid #d4d4d4; + border-bottom: none; + border-top: none; + z-index: 999999999999999999999999999999999; + /*position the autocomplete items to be the same width as the container:*/ + top: 100%; + left: 0; + right: 0; +} +.autocomplete-list { + position: absolute; + box-sizing: border-box; + margin: 0; + padding: 0; + /* border-bottom: 1px solid #d5d5d5; */ + border-top: none; + background-color: #fff; + list-style: none; + width: 12.5em; + z-index: 999999999999999999999999999999999; +} +.autocomplete-list li { + color: black; + padding: 10px; + border-bottom: 1px solid #d5d5d5; +} +#search-results { + /* display: none; */ +} +.search-results { + padding: 50; + border-top: 1px solid red; + border-top: none; + max-height: 200px; + overflow-y: auto; + position: relative; + background-color: #fff; + z-index: 99999999999999999999999; + top: 100%; + /* Position directly below the search input */ + left: 0; + /* Align with the left edge of the search input */ + width: 100%; + /* Match the width of the search input */ + list-style: none; + /* Remove default list styling */ + border-radius: 5px 0 0 5px; +} +.autocomplete-list a { + text-decoration: none; +} +.autocomplete-items div { + padding: 10px; + cursor: pointer; + background-color: #fff; + border-bottom: 1px solid #d4d4d4; +} +.autocomplete-list a:hover { + /*when hovering an item:*/ + background-color: #e9e9e9; +} +.autocomplete-active { + /*when navigating through the items using the arrow keys:*/ + background-color: DodgerBlue !important; + color: #ffffff; +} diff --git a/js/demos/search.js b/js/demos/search.js new file mode 100644 index 00000000..ce814415 --- /dev/null +++ b/js/demos/search.js @@ -0,0 +1,4 @@ +import search from '../modules/search.js'; + +//search.init(); +search.init2(); diff --git a/js/modules/es4/search.js b/js/modules/es4/search.js new file mode 100644 index 00000000..2293775a --- /dev/null +++ b/js/modules/es4/search.js @@ -0,0 +1,178 @@ +//import FlexSearch from '../../node_modules/flexsearch/dist/flexsearch.bundle.module.min'; + +//const FlexSearch = require("flexsearch"); + +//import data from "./search.json"; + +const search = new (function() { + //const FlexSearch = require('flexsearch'); + + let curSearch; + let inputTarget = null; + + this.init = () => { + + // Step 1: Example data this needs to be extracted from website in this form final result is shown here + const documents = [ + { id: '1', title: 'Sample Title 1', description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.' }, + { id: '2', title: 'Sample Title 2', description: 'Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.' }, + // Add more documents as needed + ]; + + // Step 2: Adding index/document to the library + var index = new FlexSearch.Document({ + tokenize: "forward", + cache: 100, + document: { + id: 'id', + store: [ + "title", "description" + ], + index: ["title", "description"] + } + }); + + documents.forEach(item => { + index.add({ + id: item.id, + title: item.title, + description: item.description + }); + }); + + + // Step 3: Searching + const query = 'sample'; // Example search query + const results = index.search(query); + + console.log('Results here!!!!') + + // Step 4: Display search results + console.log(results); + + + + + + } + + + this.init2 = () => { + const documents = [ + { id: 1, title: 'Moby Dick', author: { name: 'Herman Melville' }, pubDate: new Date(1851, 9, 18) }, + { id: 2, title: 'Zen and the Art of Motorcycle Maintenance', author: { name: 'Robert Pirsig' }, pubDate: new Date(1974, 3, 1) }, + { id: 3, title: 'Neuromancer', author: { name: 'William Gibson' }, pubDate: new Date(1984, 6, 1) }, + { id: 4, title: 'Zen in the Art of Archery', author: { name: 'Eugen Herrigel' }, pubDate: new Date(1948, 0, 1), link: "" }, + // ...and more + ] + + + const miniSearch = new MiniSearch({ + fields: ['title', 'keywords'], // fields to index for full-text search + storeFields: ['title', 'link'] // fields to return with search results + }) + //miniSearch.addAll(documents) + fetch('/json/search.json') + .then(response => response.json()) + .then(data => { + console.log(data) + + // Index all documents + + return miniSearch.addAll(data) + + }) + .catch(error => { + console.error('Error fetching the JSON file:', error); + }); + + + + + + + + // Search with default options + + // console.log('search results', results) + + ///Add event listener + // Handling the input event for the search bar + document.getElementById('search-input').addEventListener('input', function(e) { + + inputTarget = e.target; + // console.log(e.target) + closeAllLists(); + const searchTerm = this.value; + const list = document.getElementById('search-results'); + list.style.display = 'block'; + // list.innerHTML = ''; + let filteredItems = miniSearch.search(searchTerm, { prefix: false, fuzzy: 1 }) + let auto = miniSearch.autoSuggest(searchTerm); + console.log('auto', auto) + + const a = document.getElementById('autocomplete-items'); + + if (searchTerm && searchTerm !== curSearch) { + + + // const filteredItems = results[0].result; + filteredItems.forEach(item => { + const listItem = document.createElement('li'); + //console.log('map', item) + listItem.textContent = item.title; + listItem.classList.add('search-result-item'); + //list.appendChild(listItem); + + var link = document.createElement('a'); + link.href = item.link; + + + // const listItem = document.createElement('DIV'); + // listItem.textContent = `

${item.title}

`; + + link.append(listItem) + list.append(link) + + + + // a.appendChild(link); + + + }); + } + + curSearch = searchTerm; + }); + + function closeAllLists() { + + /*close all autocomplete lists in the document, + except the one passed as an argument:*/ + var list = document.getElementById("search-results"); + while (list.firstChild){ + list.firstChild.remove(); + } + //list.style.display = 'none' + } + + + + document.addEventListener("click", function (e) { + + if (e.target != inputTarget){ + closeAllLists(e.target); + } + + }); + + //console.log("results2", results) + + } + function execute() { + + } + + + +}) \ No newline at end of file diff --git a/js/modules/search.js b/js/modules/search.js new file mode 100644 index 00000000..a9c228fa --- /dev/null +++ b/js/modules/search.js @@ -0,0 +1,183 @@ +//import FlexSearch from '../../node_modules/flexsearch/dist/flexsearch.bundle.module.min'; + +//const FlexSearch = require("flexsearch"); + +//import data from "./search.json"; + +const search = new function () { + //const FlexSearch = require('flexsearch'); + + let curSearch; + let inputTarget = null; + + this.init = () => { + + // Step 1: Example data this needs to be extracted from website in this form final result is shown here + const documents = [ + { id: '1', title: 'Sample Title 1', description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.' }, + { id: '2', title: 'Sample Title 2', description: 'Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.' }, + // Add more documents as needed + ]; + + // Step 2: Adding index/document to the library + var index = new FlexSearch.Document({ + tokenize: "forward", + cache: 100, + document: { + id: 'id', + store: [ + "title", "description" + ], + index: ["title", "description"] + } + }); + + documents.forEach(item => { + index.add({ + id: item.id, + title: item.title, + description: item.description + }); + }); + + + // Step 3: Searching + const query = 'sample'; // Example search query + const results = index.search(query); + + console.log('Results here!!!!') + + // Step 4: Display search results + console.log(results); + + + + + + } + + + this.init2 = () => { + const documents = [ + { id: 1, title: 'Moby Dick', author: { name: 'Herman Melville' }, pubDate: new Date(1851, 9, 18) }, + { id: 2, title: 'Zen and the Art of Motorcycle Maintenance', author: { name: 'Robert Pirsig' }, pubDate: new Date(1974, 3, 1) }, + { id: 3, title: 'Neuromancer', author: { name: 'William Gibson' }, pubDate: new Date(1984, 6, 1) }, + { id: 4, title: 'Zen in the Art of Archery', author: { name: 'Eugen Herrigel' }, pubDate: new Date(1948, 0, 1), link: "" }, + // ...and more + ] + + + const miniSearch = new MiniSearch({ + fields: ['title', 'keywords'], // fields to index for full-text search + storeFields: ['title', 'link'] // fields to return with search results + }) + //miniSearch.addAll(documents) + fetch('/json/search.json') + .then(response => response.json()) + .then(data => { + console.log(data) + + // Index all documents + + return miniSearch.addAll(data) + + }) + .catch(error => { + console.error('Error fetching the JSON file:', error); + }); + + + + + + + + // Search with default options + + // console.log('search results', results) + + ///Add event listener + // Handling the input event for the search bar + document.getElementById('search-input').addEventListener('input', function(e) { + + inputTarget = e.target; + // console.log(e.target) + closeAllLists(); + const searchTerm = this.value; + const list = document.getElementById('search-results'); + list.style.display = 'block'; + // list.innerHTML = ''; + let filteredItems = miniSearch.search(searchTerm, { prefix: false, fuzzy: 1 }) + let auto = miniSearch.autoSuggest(searchTerm); + console.log('auto', auto) + + const a = document.getElementById('autocomplete-items'); + + if (searchTerm && searchTerm !== curSearch) { + + + // const filteredItems = results[0].result; + filteredItems.forEach(item => { + const listItem = document.createElement('li'); + //console.log('map', item) + listItem.textContent = item.title; + listItem.classList.add('search-result-item'); + //list.appendChild(listItem); + + var link = document.createElement('a'); + link.href = item.link; + + + // const listItem = document.createElement('DIV'); + // listItem.textContent = `

${item.title}

`; + + link.append(listItem) + list.append(link) + + + + // a.appendChild(link); + + + }); + } + + curSearch = searchTerm; + }); + + function closeAllLists() { + + /*close all autocomplete lists in the document, + except the one passed as an argument:*/ + var list = document.getElementById("search-results"); + while (list.firstChild){ + list.firstChild.remove(); + } + //list.style.display = 'none' + } + + + + document.addEventListener("click", function (e) { + + if (e.target != inputTarget){ + closeAllLists(e.target); + } + + }); + + //console.log("results2", results) + + } + function execute() { + + } + + + +} + + + + +export default search; \ No newline at end of file diff --git a/json/search.json b/json/search.json new file mode 100644 index 00000000..0546361f --- /dev/null +++ b/json/search.json @@ -0,0 +1,44 @@ +[ + { + "id": 1, + "title": "Tooltip", + "content": "This article includes best practices on accessible tooltips", + "keywords": "Simple controls, ", + "link": "/tooltip.php" + }, + { + "id": 2, + "title": "Accessible Form Structure", + "content": "Best practices for accessible form structure", + "keywords": "Form UX patterns", + "link": "/form.php" + }, + { + "id": 3, + "title": "Accessible Form Validation", + "content": "Best practices for form validation", + "keywords": "Form UX Patterns,", + "link": "/form-error-checking.php" + }, + { + "id": 4, + "title": "Search Forms", + "content": "Best practices for search forms", + "keywords": "Form UX Patterns", + "link": "/search.php" + }, + { + "id": 5, + "title": "Accessible Buttons", + "content": "Best practices for buttons", + "keywords": "Form Elements,", + "link": "/button.php" + }, + { + "id": 6, + "title": "Accessible Checkboxes", + "content": "Best practices for form checkboxes", + "keywords": "Form Elements,", + "link": "/checkbox.php" + } +] diff --git a/less/site-search.less b/less/site-search.less new file mode 100644 index 00000000..96fd5f51 --- /dev/null +++ b/less/site-search.less @@ -0,0 +1,118 @@ +.search-button { + width: 28px; + height: 100%; + border: 1px solid #4e7963; + background: #4e7963; + text-align: center; + color: #fff; + border-radius: 0 5px 5px 0; + cursor: pointer; + margin: 0 !important; + position: relative; + left: -4px; +} + +.search { +} + +.search-input { + padding: 5px; +} + +.search-bar { + display: flex; +} + +.search-bar-home { + padding: 1ex 0.5em; + width: 20em; + font-size: 1.3rem; + line-height: 1; + background: #fff; + border: 1px solid #d5d5d5; + border-radius: 2px; + box-shadow: inset 0 5px 5px -5px rgba(0, 0, 0, 0.2); + box-sizing: border-box; +} + +.autocomplete { + /*the container must be positioned relative:*/ + position: relative; +} + +.search-example-2 { + position: relative; + left: 0; + width: 20em; +} + +.autocomplete-items { + position: absolute; + border: 1px solid #d4d4d4; + border-bottom: none; + border-top: none; + z-index: 999999999999999999999999999999999; + /*position the autocomplete items to be the same width as the container:*/ + top: 100%; + left: 0; + right: 0; +} + +.autocomplete-list { + position: absolute; + box-sizing: border-box; + margin: 0; + padding: 0; + /* border-bottom: 1px solid #d5d5d5; */ + border-top: none; + background-color: #fff; + list-style: none; + width: 12.5em; + z-index: 999999999999999999999999999999999; +} + +.autocomplete-list li { + color: black; + padding: 10px; + border-bottom: 1px solid #d5d5d5; +} + +#search-results { + /* display: none; */ +} + +.search-results { + padding: 50; + border-top: 1px solid red; + border-top: none; + max-height: 200px; + overflow-y: auto; + position: relative; + background-color: #fff; + z-index: 99999999999999999999999; + top: 100%; /* Position directly below the search input */ + left: 0; /* Align with the left edge of the search input */ + width: 100%; /* Match the width of the search input */ + list-style: none; /* Remove default list styling */ + border-radius: 5px 0 0 5px; +} + +.autocomplete-list a { + text-decoration: none; +} + +.autocomplete-items div { + padding: 10px; + cursor: pointer; + background-color: #fff; + border-bottom: 1px solid #d4d4d4; +} +.autocomplete-list a:hover { + /*when hovering an item:*/ + background-color: #e9e9e9; +} +.autocomplete-active { + /*when navigating through the items using the arrow keys:*/ + background-color: DodgerBlue !important; + color: #ffffff; +} diff --git a/templates/includes/documentation-header.php b/templates/includes/documentation-header.php index 5620f40d..b151a311 100755 --- a/templates/includes/documentation-header.php +++ b/templates/includes/documentation-header.php @@ -14,6 +14,36 @@ + +
+ + +
+ + + @@ -171,7 +201,192 @@ class="enable-flyout enable-flyout__level enable-flyout__dropdown"> + + + + + + + +