| 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 24 */ |
24 */ |
| 25 |
25 |
| 26 function debounce(func){ |
26 function debounce(func){ |
| 27 let timer; |
27 let timer; |
| 28 return () => { |
28 return (...args) => { |
| 29 clearTimeout(timer); |
29 clearTimeout(timer); |
| 30 timer = setTimeout(() => { func.apply(this); }, 300); |
30 timer = setTimeout(() => { func.apply(this, args); }, 300); |
| 31 }; |
31 }; |
| 32 } |
32 } |
| 33 |
33 |
| 34 const issueSearch = debounce(() => issueSearchImpl()) |
|
| 35 let searchBoxOldContent = ''; |
34 let searchBoxOldContent = ''; |
| 36 function issueSearchImpl() { |
35 function issueSearchImpl(elementId, project) { |
| 37 const searchBox = document.getElementById('search-box'); |
36 const searchBox = document.getElementById(elementId); |
| 38 if (searchBoxOldContent !== searchBox.value) { |
37 if (searchBoxOldContent !== searchBox.value) { |
| 39 searchBoxOldContent = searchBox.value; |
38 searchBoxOldContent = searchBox.value; |
| 40 const req = new XMLHttpRequest(); |
39 const req = new XMLHttpRequest(); |
| 41 req.addEventListener("load", (evt) => { |
40 req.addEventListener("load", (evt) => { |
| 42 const dataList = document.getElementById('search-box-list'); |
41 const dataList = document.getElementById(elementId+'-list'); |
| 43 dataList.innerHTML = ''; |
42 dataList.innerHTML = ''; |
| 44 JSON.parse(evt.target.responseText).forEach(function(item){ |
43 JSON.parse(evt.target.responseText).forEach(function(item){ |
| 45 const option = document.createElement('option'); |
44 const option = document.createElement('option'); |
| 46 option.value = item; |
45 option.value = item; |
| 47 dataList.appendChild(option); |
46 dataList.appendChild(option); |
| 48 }); |
47 }); |
| 49 }); |
48 }); |
| 50 req.open("GET", baseHref+'issues/search?q='+encodeURIComponent(searchBox.value)); |
49 let url = baseHref+'issues/search?q='+encodeURIComponent(searchBox.value); |
| |
50 if (project > 0) url+='&p='+project; |
| |
51 req.open("GET", url); |
| 51 req.send(); |
52 req.send(); |
| 52 } |
53 } |
| 53 } |
54 } |
| |
55 const issueSearch = debounce((elementId, project = 0) => issueSearchImpl(elementId, project)) |
| 54 |
56 |
| 55 // configure the search box |
57 function configureSearchBox(elementId, project, navigateOnEnter = false) { |
| 56 window.addEventListener('load', () => { |
58 const searchBox = document.getElementById(elementId); |
| 57 const searchBox = document.getElementById('search-box'); |
59 searchBox.addEventListener('change', () => issueSearch(elementId, project)); |
| 58 searchBox.addEventListener('change', () => issueSearch()) |
60 if (navigateOnEnter) { |
| 59 searchBox.addEventListener('keyup', (evt) => { |
61 searchBox.addEventListener('keyup', (evt) => { |
| 60 if (evt.code === 'Enter' || evt.code === 'NumpadEnter') { |
62 if (evt.code === 'Enter' || evt.code === 'NumpadEnter') { |
| 61 let stext = searchBox.value.trim() |
63 let stext = searchBox.value.trim() |
| 62 if (stext.length === 0) return; |
64 if (stext.length === 0) return; |
| 63 if (stext[0] === '#') stext = stext.substring(1); |
65 if (stext[0] === '#') stext = stext.substring(1); |
| 64 const snum = Number.parseInt(stext.split(' ')[0], 10); |
66 const snum = Number.parseInt(stext.split(' ')[0], 10); |
| 65 if (snum !== Number.NaN) { |
67 if (snum !== Number.NaN) { |
| 66 location.assign(baseHref+'issues/'+snum+'?in_project=true'); |
68 location.assign(baseHref + 'issues/' + snum + '?in_project=true'); |
| |
69 } |
| |
70 } else { |
| |
71 issueSearch(elementId, project); |
| 67 } |
72 } |
| 68 } else { |
73 }) |
| 69 issueSearch(); |
74 } else { |
| 70 } |
75 searchBox.addEventListener('keyup', () => issueSearch(elementId, project)); |
| 71 }) |
76 } |
| 72 }); |
77 } |
| 73 |
78 |
| |
79 // configure the global search box |
| |
80 window.addEventListener('load', () => configureSearchBox('search-box', 0, true)); |
| |
81 |