##// END OF EJS Templates
go-to search: updated logic of goto switcher...
marcink -
r3556:a75b51f8 default
parent child Browse files
Show More
@@ -33,7 +33,7 b' from rhodecode.lib.index import searcher'
33 33 from rhodecode.lib.utils2 import safe_unicode, str2bool, safe_int
34 34 from rhodecode.lib.ext_json import json
35 35 from rhodecode.model.db import (
36 func, true, or_, in_filter_generator, Repository, RepoGroup, User, UserGroup)
36 func, true, or_, case, in_filter_generator, Repository, RepoGroup, User, UserGroup)
37 37 from rhodecode.model.repo import RepoModel
38 38 from rhodecode.model.repo_group import RepoGroupModel
39 39 from rhodecode.model.scm import RepoGroupList, RepoList
@@ -105,21 +105,27 b' class HomeView(BaseAppView):'
105 105
106 106 return {'suggestions': _user_groups}
107 107
108 def _get_repo_list(self, name_contains=None, repo_type=None, limit=20):
108 def _get_repo_list(self, name_contains=None, repo_type=None, repo_group_name='', limit=20):
109 109 org_query = name_contains
110 110 allowed_ids = self._rhodecode_user.repo_acl_ids(
111 111 ['repository.read', 'repository.write', 'repository.admin'],
112 112 cache=False, name_filter=name_contains) or [-1]
113 113
114 114 query = Repository.query()\
115 .order_by(func.length(Repository.repo_name))\
116 .order_by(Repository.repo_name)\
117 115 .filter(Repository.archived.isnot(true()))\
118 116 .filter(or_(
119 117 # generate multiple IN to fix limitation problems
120 118 *in_filter_generator(Repository.repo_id, allowed_ids)
121 119 ))
122 120
121 query = query.order_by(case(
122 [
123 (Repository.repo_name.startswith(repo_group_name), repo_group_name+'/'),
124 ],
125 ))
126 query = query.order_by(func.length(Repository.repo_name))
127 query = query.order_by(Repository.repo_name)
128
123 129 if repo_type:
124 130 query = query.filter(Repository.repo_type == repo_type)
125 131
@@ -145,20 +151,26 b' class HomeView(BaseAppView):'
145 151 }
146 152 for obj in acl_iter]
147 153
148 def _get_repo_group_list(self, name_contains=None, limit=20):
154 def _get_repo_group_list(self, name_contains=None, repo_group_name='', limit=20):
149 155 org_query = name_contains
150 156 allowed_ids = self._rhodecode_user.repo_group_acl_ids(
151 157 ['group.read', 'group.write', 'group.admin'],
152 158 cache=False, name_filter=name_contains) or [-1]
153 159
154 160 query = RepoGroup.query()\
155 .order_by(func.length(RepoGroup.group_name))\
156 .order_by(RepoGroup.group_name) \
157 161 .filter(or_(
158 162 # generate multiple IN to fix limitation problems
159 163 *in_filter_generator(RepoGroup.group_id, allowed_ids)
160 164 ))
161 165
166 query = query.order_by(case(
167 [
168 (RepoGroup.group_name.startswith(repo_group_name), repo_group_name+'/'),
169 ],
170 ))
171 query = query.order_by(func.length(RepoGroup.group_name))
172 query = query.order_by(RepoGroup.group_name)
173
162 174 if name_contains:
163 175 ilike_expression = u'%{}%'.format(safe_unicode(name_contains))
164 176 query = query.filter(
@@ -183,11 +195,17 b' class HomeView(BaseAppView):'
183 195 def _get_user_list(self, name_contains=None, limit=20):
184 196 org_query = name_contains
185 197 if not name_contains:
186 return []
198 return [], False
187 199
188 name_contains = re.compile('(?:user:)(.+)').findall(name_contains)
200 # TODO(marcink): should all logged in users be allowed to search others?
201 allowed_user_search = self._rhodecode_user.username != User.DEFAULT_USER
202 if not allowed_user_search:
203 return [], False
204
205 name_contains = re.compile('(?:user:[ ]?)(.+)').findall(name_contains)
189 206 if len(name_contains) != 1:
190 return []
207 return [], False
208
191 209 name_contains = name_contains[0]
192 210
193 211 query = User.query()\
@@ -207,22 +225,28 b' class HomeView(BaseAppView):'
207 225 {
208 226 'id': obj.user_id,
209 227 'value': org_query,
210 'value_display': obj.username,
228 'value_display': 'user: `{}`'.format(obj.username),
211 229 'type': 'user',
212 230 'icon_link': h.gravatar_url(obj.email, 30),
213 231 'url': h.route_path(
214 232 'user_profile', username=obj.username)
215 233 }
216 for obj in acl_iter]
234 for obj in acl_iter], True
217 235
218 236 def _get_user_groups_list(self, name_contains=None, limit=20):
219 237 org_query = name_contains
220 238 if not name_contains:
221 return []
239 return [], False
222 240
223 name_contains = re.compile('(?:user_group:)(.+)').findall(name_contains)
241 # TODO(marcink): should all logged in users be allowed to search others?
242 allowed_user_search = self._rhodecode_user.username != User.DEFAULT_USER
243 if not allowed_user_search:
244 return [], False
245
246 name_contains = re.compile('(?:user_group:[ ]?)(.+)').findall(name_contains)
224 247 if len(name_contains) != 1:
225 return []
248 return [], False
249
226 250 name_contains = name_contains[0]
227 251
228 252 query = UserGroup.query()\
@@ -241,27 +265,34 b' class HomeView(BaseAppView):'
241 265 {
242 266 'id': obj.users_group_id,
243 267 'value': org_query,
244 'value_display': obj.users_group_name,
268 'value_display': 'user_group: `{}`'.format(obj.users_group_name),
245 269 'type': 'user_group',
246 270 'url': h.route_path(
247 271 'user_group_profile', user_group_name=obj.users_group_name)
248 272 }
249 for obj in acl_iter]
273 for obj in acl_iter], True
250 274
251 def _get_hash_commit_list(self, auth_user, searcher, query):
275 def _get_hash_commit_list(self, auth_user, searcher, query, repo=None, repo_group=None):
276 repo_name = repo_group_name = None
277 if repo:
278 repo_name = repo.repo_name
279 if repo_group:
280 repo_group_name = repo_group.group_name
281
252 282 org_query = query
253 283 if not query or len(query) < 3 or not searcher:
254 return []
284 return [], False
255 285
256 commit_hashes = re.compile('(?:commit:)([0-9a-f]{2,40})').findall(query)
286 commit_hashes = re.compile('(?:commit:[ ]?)([0-9a-f]{2,40})').findall(query)
257 287
258 288 if len(commit_hashes) != 1:
259 return []
289 return [], False
290
260 291 commit_hash = commit_hashes[0]
261 292
262 293 result = searcher.search(
263 294 'commit_id:{}*'.format(commit_hash), 'commit', auth_user,
264 raise_on_exc=False)
295 repo_name, repo_group_name, raise_on_exc=False)
265 296
266 297 commits = []
267 298 for entry in result['results']:
@@ -286,22 +317,29 b' class HomeView(BaseAppView):'
286 317 }
287 318
288 319 commits.append(commit_entry)
289 return commits
320 return commits, True
290 321
291 def _get_path_list(self, auth_user, searcher, query):
322 def _get_path_list(self, auth_user, searcher, query, repo=None, repo_group=None):
323 repo_name = repo_group_name = None
324 if repo:
325 repo_name = repo.repo_name
326 if repo_group:
327 repo_group_name = repo_group.group_name
328
292 329 org_query = query
293 330 if not query or len(query) < 3 or not searcher:
294 return []
331 return [], False
295 332
296 paths_re = re.compile('(?:file:)(.{1,})').findall(query)
333 paths_re = re.compile('(?:file:[ ]?)(.+)').findall(query)
297 334 if len(paths_re) != 1:
298 return []
335 return [], False
336
299 337 file_path = paths_re[0]
300 338
301 339 search_path = searcher.escape_specials(file_path)
302 340 result = searcher.search(
303 341 'file.raw:*{}*'.format(search_path), 'path', auth_user,
304 raise_on_exc=False)
342 repo_name, repo_group_name, raise_on_exc=False)
305 343
306 344 files = []
307 345 for entry in result['results']:
@@ -327,7 +365,7 b' class HomeView(BaseAppView):'
327 365 }
328 366
329 367 files.append(file_entry)
330 return files
368 return files, True
331 369
332 370 @LoginRequired()
333 371 @view_config(
@@ -405,17 +443,15 b' class HomeView(BaseAppView):'
405 443 qry = query
406 444 return {'q': qry, 'type': 'content'}
407 445 label = u'File search for `{}` in this repository.'.format(query)
408 queries.append(
409 {
410 'id': -10,
411 'value': query,
412 'value_display': label,
413 'type': 'search',
414 'url': h.route_path('search_repo',
415 repo_name=repo_name,
416 _query=query_modifier())
446 file_qry = {
447 'id': -10,
448 'value': query,
449 'value_display': label,
450 'type': 'search',
451 'url': h.route_path('search_repo',
452 repo_name=repo_name,
453 _query=query_modifier())
417 454 }
418 )
419 455
420 456 # commits
421 457 def query_modifier():
@@ -423,17 +459,22 b' class HomeView(BaseAppView):'
423 459 return {'q': qry, 'type': 'commit'}
424 460
425 461 label = u'Commit search for `{}` in this repository.'.format(query)
426 queries.append(
427 {
428 'id': -20,
429 'value': query,
430 'value_display': label,
431 'type': 'search',
432 'url': h.route_path('search_repo',
433 repo_name=repo_name,
434 _query=query_modifier())
462 commit_qry = {
463 'id': -20,
464 'value': query,
465 'value_display': label,
466 'type': 'search',
467 'url': h.route_path('search_repo',
468 repo_name=repo_name,
469 _query=query_modifier())
435 470 }
436 )
471
472 if repo_context in ['commit', 'changelog']:
473 queries.extend([commit_qry, file_qry])
474 elif repo_context in ['files', 'summary']:
475 queries.extend([file_qry, commit_qry])
476 else:
477 queries.extend([commit_qry, file_qry])
437 478
438 479 elif is_es_6 and repo_group_name:
439 480 # files
@@ -442,17 +483,15 b' class HomeView(BaseAppView):'
442 483 return {'q': qry, 'type': 'content'}
443 484
444 485 label = u'File search for `{}` in this repository group'.format(query)
445 queries.append(
446 {
447 'id': -30,
448 'value': query,
449 'value_display': label,
450 'type': 'search',
451 'url': h.route_path('search_repo_group',
452 repo_group_name=repo_group_name,
453 _query=query_modifier())
486 file_qry = {
487 'id': -30,
488 'value': query,
489 'value_display': label,
490 'type': 'search',
491 'url': h.route_path('search_repo_group',
492 repo_group_name=repo_group_name,
493 _query=query_modifier())
454 494 }
455 )
456 495
457 496 # commits
458 497 def query_modifier():
@@ -460,18 +499,24 b' class HomeView(BaseAppView):'
460 499 return {'q': qry, 'type': 'commit'}
461 500
462 501 label = u'Commit search for `{}` in this repository group'.format(query)
463 queries.append(
464 {
465 'id': -40,
466 'value': query,
467 'value_display': label,
468 'type': 'search',
469 'url': h.route_path('search_repo_group',
470 repo_group_name=repo_group_name,
471 _query=query_modifier())
502 commit_qry = {
503 'id': -40,
504 'value': query,
505 'value_display': label,
506 'type': 'search',
507 'url': h.route_path('search_repo_group',
508 repo_group_name=repo_group_name,
509 _query=query_modifier())
472 510 }
473 )
474 511
512 if repo_context in ['commit', 'changelog']:
513 queries.extend([commit_qry, file_qry])
514 elif repo_context in ['files', 'summary']:
515 queries.extend([file_qry, commit_qry])
516 else:
517 queries.extend([commit_qry, file_qry])
518
519 # Global, not scoped
475 520 if not queries:
476 521 queries.append(
477 522 {
@@ -510,65 +555,107 b' class HomeView(BaseAppView):'
510 555 if not query:
511 556 return {'suggestions': res}
512 557
558 def no_match(name):
559 return {
560 'id': -1,
561 'value': "",
562 'value_display': name,
563 'type': 'text',
564 'url': ""
565 }
513 566 searcher = searcher_from_config(self.request.registry.settings)
514 for _q in self._get_default_search_queries(self.request.GET, searcher, query):
515 res.append(_q)
567 has_specialized_search = False
516 568
569 # set repo context
570 repo = None
571 repo_id = safe_int(self.request.GET.get('search_context[repo_id]'))
572 if repo_id:
573 repo = Repository.get(repo_id)
574
575 # set group context
576 repo_group = None
517 577 repo_group_id = safe_int(self.request.GET.get('search_context[repo_group_id]'))
518 578 if repo_group_id:
519 579 repo_group = RepoGroup.get(repo_group_id)
520 composed_hint = '{}/{}'.format(repo_group.group_name, query)
521 show_hint = not query.startswith(repo_group.group_name)
522 if repo_group and show_hint:
523 hint = u'Repository search inside: `{}`'.format(composed_hint)
524 res.append({
525 'id': -1,
526 'value': composed_hint,
527 'value_display': hint,
528 'type': 'hint',
529 'url': ""
530 })
580 prefix_match = False
581
582 # user: type search
583 if not prefix_match:
584 users, prefix_match = self._get_user_list(query)
585 if users:
586 has_specialized_search = True
587 for serialized_user in users:
588 res.append(serialized_user)
589 elif prefix_match:
590 has_specialized_search = True
591 res.append(no_match('No matching users found'))
531 592
532 repo_groups = self._get_repo_group_list(query)
533 for serialized_repo_group in repo_groups:
534 res.append(serialized_repo_group)
593 # user_group: type search
594 if not prefix_match:
595 user_groups, prefix_match = self._get_user_groups_list(query)
596 if user_groups:
597 has_specialized_search = True
598 for serialized_user_group in user_groups:
599 res.append(serialized_user_group)
600 elif prefix_match:
601 has_specialized_search = True
602 res.append(no_match('No matching user groups found'))
535 603
536 repos = self._get_repo_list(query)
537 for serialized_repo in repos:
538 res.append(serialized_repo)
604 # FTS commit: type search
605 if not prefix_match:
606 commits, prefix_match = self._get_hash_commit_list(
607 c.auth_user, searcher, query, repo, repo_group)
608 if commits:
609 has_specialized_search = True
610 unique_repos = collections.OrderedDict()
611 for commit in commits:
612 repo_name = commit['repo']
613 unique_repos.setdefault(repo_name, []).append(commit)
539 614
540 # TODO(marcink): should all logged in users be allowed to search others?
541 allowed_user_search = self._rhodecode_user.username != User.DEFAULT_USER
542 if allowed_user_search:
543 users = self._get_user_list(query)
544 for serialized_user in users:
545 res.append(serialized_user)
615 for _repo, commits in unique_repos.items():
616 for commit in commits:
617 res.append(commit)
618 elif prefix_match:
619 has_specialized_search = True
620 res.append(no_match('No matching commits found'))
546 621
547 user_groups = self._get_user_groups_list(query)
548 for serialized_user_group in user_groups:
549 res.append(serialized_user_group)
622 # FTS file: type search
623 if not prefix_match:
624 paths, prefix_match = self._get_path_list(
625 c.auth_user, searcher, query, repo, repo_group)
626 if paths:
627 has_specialized_search = True
628 unique_repos = collections.OrderedDict()
629 for path in paths:
630 repo_name = path['repo']
631 unique_repos.setdefault(repo_name, []).append(path)
550 632
551 commits = self._get_hash_commit_list(c.auth_user, searcher, query)
552 if commits:
553 unique_repos = collections.OrderedDict()
554 for commit in commits:
555 repo_name = commit['repo']
556 unique_repos.setdefault(repo_name, []).append(commit)
633 for repo, paths in unique_repos.items():
634 for path in paths:
635 res.append(path)
636 elif prefix_match:
637 has_specialized_search = True
638 res.append(no_match('No matching files found'))
557 639
558 for repo, commits in unique_repos.items():
559 for commit in commits:
560 res.append(commit)
640 # main suggestions
641 if not has_specialized_search:
642 repo_group_name = ''
643 if repo_group:
644 repo_group_name = repo_group.group_name
561 645
562 paths = self._get_path_list(c.auth_user, searcher, query)
563 if paths:
564 unique_repos = collections.OrderedDict()
565 for path in paths:
566 repo_name = path['repo']
567 unique_repos.setdefault(repo_name, []).append(path)
646 for _q in self._get_default_search_queries(self.request.GET, searcher, query):
647 res.append(_q)
648
649 repo_groups = self._get_repo_group_list(query, repo_group_name=repo_group_name)
650 for serialized_repo_group in repo_groups:
651 res.append(serialized_repo_group)
568 652
569 for repo, paths in unique_repos.items():
570 for path in paths:
571 res.append(path)
653 repos = self._get_repo_list(query, repo_group_name=repo_group_name)
654 for serialized_repo in repos:
655 res.append(serialized_repo)
656
657 if not repos and not repo_groups:
658 res.append(no_match('No matches found'))
572 659
573 660 return {'suggestions': res}
574 661
@@ -2037,6 +2037,6 b' def get_repo_view_type(request):'
2037 2037 'repo_files': 'files',
2038 2038 'repo_summary': 'summary',
2039 2039 'repo_commit': 'commit'
2040 }
2040 2041
2041 }
2042 2042 return route_to_view_type.get(route_name)
@@ -39,7 +39,7 b' from sqlalchemy import ('
39 39 Index, Sequence, UniqueConstraint, ForeignKey, CheckConstraint, Column,
40 40 Boolean, String, Unicode, UnicodeText, DateTime, Integer, LargeBinary,
41 41 Text, Float, PickleType)
42 from sqlalchemy.sql.expression import true, false
42 from sqlalchemy.sql.expression import true, false, case
43 43 from sqlalchemy.sql.functions import coalesce, count # pragma: no cover
44 44 from sqlalchemy.orm import (
45 45 relationship, joinedload, class_mapper, validates, aliased)
@@ -644,6 +644,40 b' ul#context-pages {'
644 644
645 645 .main_filter_input_box {
646 646 display: inline-block;
647
648 .searchItems {
649 display:flex;
650 background: #666666;
651 padding: 0px;
652
653 a {
654 border: none !important;
655 }
656 }
657
658 .searchTag {
659 line-height: 28px;
660 padding: 0px 4px;
661
662 .tag {
663 color: @nav-grey;
664 border-color: @nav-grey;
665 }
666 }
667
668 .searchTagFilter {
669 background-color: @grey3 !important;
670 }
671
672 .searchTagHelp {
673 background-color: @grey2 !important;
674 }
675 .searchTagHelp:hover {
676 background-color: @grey2 !important;
677 }
678 .searchTagInput {
679 background-color: @grey3 !important;
680 }
647 681 }
648 682
649 683 .main_filter_box {
@@ -667,7 +701,8 b' ul#context-pages {'
667 701 color: @nav-grey;
668 702 background: @grey3;
669 703 min-height: 18px;
670
704 border:none;
705 border-radius: 0;
671 706
672 707 &:active {
673 708 color: @grey2 !important;
@@ -528,7 +528,19 b''
528 528 if ($.isFunction(serviceUrl)) {
529 529 serviceUrl = serviceUrl.call(that.element, query);
530 530 }
531 cacheKey = serviceUrl + '?' + $.param(params || {});
531
532 var callParams = {};
533 //make an evaluated copy of params
534 $.each(params, function(index, value) {
535 if($.isFunction(value)){
536 callParams[index] = value();
537 }
538 else {
539 callParams[index] = value;
540 }
541 });
542
543 cacheKey = serviceUrl + '?' + $.param(callParams);
532 544 response = that.cachedResponse[cacheKey];
533 545 }
534 546
@@ -536,7 +548,7 b''
536 548 that.suggestions = response.suggestions;
537 549 that.suggest();
538 550 } else if (!that.isBadQuery(query)) {
539 if (options.onSearchStart.call(that.element, options.params) === false) {
551 if (options.onSearchStart.call(that.element, params) === false) {
540 552 return;
541 553 }
542 554 if (that.currentRequest) {
@@ -233,7 +233,6 b''
233 233 <li class="${is_active('changelog')}"><a class="menulink" href="${h.route_path('repo_changelog', repo_name=c.repo_name)}"><div class="menulabel">${_('Changelog')}</div></a></li>
234 234 <li class="${is_active('files')}"><a class="menulink" href="${h.route_path('repo_files', repo_name=c.repo_name, commit_id=c.rhodecode_db_repo.landing_rev[1], f_path='')}"><div class="menulabel">${_('Files')}</div></a></li>
235 235 <li class="${is_active('compare')}"><a class="menulink" href="${h.route_path('repo_compare_select',repo_name=c.repo_name)}"><div class="menulabel">${_('Compare')}</div></a></li>
236 <li class="${is_active('search')}"><a class="menulink" href="${h.route_path('search_repo',repo_name=c.repo_name)}"><div class="menulabel">${_('Search')}</div></a></li>
237 236
238 237 ## TODO: anderson: ideally it would have a function on the scm_instance "enable_pullrequest() and enable_fork()"
239 238 %if c.rhodecode_db_repo.repo_type in ['git','hg']:
@@ -338,7 +337,6 b''
338 337 <div class="wrapper">
339 338 <ul id="context-pages" class="navigation horizontal-list">
340 339 <li class="${is_active('home')}"><a class="menulink" href="${h.route_path('repo_group_home', repo_group_name=c.repo_group.group_name)}"><div class="menulabel">${_('Group Home')}</div></a></li>
341 <li class="${is_active('search')}"><a class="menulink" href="${h.route_path('search_repo_group', repo_group_name=c.repo_group.group_name)}"><div class="menulabel">${_('Search')}</div></a></li>
342 340
343 341 <li class="${is_active('options')}">
344 342 <a class="menulink dropdown">
@@ -486,10 +484,35 b''
486 484 <li>
487 485 <div class="menulabel main_filter_box">
488 486 <div class="main_filter_input_box">
489 <input class="main_filter_input" id="main_filter" size="15" type="text" name="main_filter" placeholder="${_('search / go to...')}" value=""/>
490 </div>
491 <div class="main_filter_help_box">
492 <a href="#showFilterHelp" onclick="showMainFilterBox(); return false">?</a>
487 <ul class="searchItems">
488
489 % if c.template_context['search_context']['repo_id']:
490 <li class="searchTag searchTagFilter searchTagHidable" >
491 ##<a href="${h.route_path('search_repo',repo_name=c.template_context['search_context']['repo_name'])}">
492 <span class="tag">
493 This repo
494 <a href="#removeGoToFilter" onclick="removeGoToFilter(); return false"><i class="icon-delete"></i></a>
495 </span>
496 ##</a>
497 </li>
498 % elif c.template_context['search_context']['repo_group_id']:
499 <li class="searchTag searchTagFilter searchTagHidable">
500 ##<a href="${h.route_path('search_repo_group',repo_group_name=c.template_context['search_context']['repo_group_name'])}">
501 <span class="tag">
502 This group
503 <a href="#removeGoToFilter" onclick="removeGoToFilter(); return false"><i class="icon-delete"></i></a>
504 </span>
505 ##</a>
506 </li>
507 % endif
508
509 <li class="searchTagInput">
510 <input class="main_filter_input" id="main_filter" size="15" type="text" name="main_filter" placeholder="${_('search / go to...')}" value="" />
511 </li>
512 <li class="searchTag searchTagHelp">
513 <a href="#showFilterHelp" onclick="showMainFilterBox(); return false">?</a>
514 </li>
515 </ul>
493 516 </div>
494 517 </div>
495 518
@@ -500,13 +523,21 b''
500 523
501 524 - Prefix query to allow special search:
502 525
503 user:admin, to search for usernames
526 user:admin, to search for usernames, always global
527
528 user_group:devops, to search for user groups, always global
504 529
505 user_group:devops, to search for user groups
530 commit:efced4, to search for commits, scoped to repositories or groups
531
532 file:models.py, to search for file paths, scoped to repositories or groups
506 533
507 commit:efced4, to search for commits
508
509 file:models.py, to search for file paths
534 % if c.template_context['search_context']['repo_id']:
535 For advanced full text search visit: <a href="${h.route_path('search_repo',repo_name=c.template_context['search_context']['repo_name'])}">repository search</a>
536 % elif c.template_context['search_context']['repo_group_id']:
537 For advanced full text search visit: <a href="${h.route_path('search_repo_group',repo_group_name=c.template_context['search_context']['repo_group_name'])}">repository group search</a>
538 % else:
539 For advanced full text search visit: <a href="${h.route_path('search')}">global search</a>
540 % endif
510 541 </div>
511 542 </li>
512 543
@@ -622,6 +653,22 b''
622 653 }(result, escapeMarkup);
623 654 };
624 655
656 var escapeRegExChars = function (value) {
657 return value.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
658 };
659
660 var getRepoIcon = function(repo_type) {
661 if (repo_type === 'hg') {
662 return '<i class="icon-hg"></i> ';
663 }
664 else if (repo_type === 'git') {
665 return '<i class="icon-git"></i> ';
666 }
667 else if (repo_type === 'svn') {
668 return '<i class="icon-svn"></i> ';
669 }
670 return ''
671 };
625 672
626 673 var autocompleteMainFilterFormatResult = function (data, value, org_formatter) {
627 674
@@ -632,27 +679,14 b''
632 679 var searchType = data['type'];
633 680 var valueDisplay = data['value_display'];
634 681
635 var escapeRegExChars = function (value) {
636 return value.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
637 };
638 682 var pattern = '(' + escapeRegExChars(value) + ')';
639 683
640 var getRepoIcon = function(repo_type) {
641 if (repo_type === 'hg') {
642 return '<i class="icon-hg"></i> ';
643 }
644 else if (repo_type === 'git') {
645 return '<i class="icon-git"></i> ';
646 }
647 else if (repo_type === 'svn') {
648 return '<i class="icon-svn"></i> ';
649 }
650 return ''
651 };
684 valueDisplay = Select2.util.escapeMarkup(valueDisplay);
652 685
653 686 // highlight match
654 valueDisplay = Select2.util.escapeMarkup(valueDisplay);
655 valueDisplay = valueDisplay.replace(new RegExp(pattern, 'gi'), '<strong>$1<\/strong>');
687 if (searchType != 'text') {
688 valueDisplay = valueDisplay.replace(new RegExp(pattern, 'gi'), '<strong>$1<\/strong>');
689 }
656 690
657 691 var icon = '';
658 692
@@ -684,6 +718,7 b''
684 718 else if (searchType === 'user_group') {
685 719 icon += '<i class="icon-group"></i> ';
686 720 }
721 // user
687 722 else if (searchType === 'user') {
688 723 icon += '<img class="gravatar" src="{0}"/>'.format(data['icon_link']);
689 724 }
@@ -707,6 +742,10 b''
707 742 icon += '<i class="icon-tag"></i>';
708 743 }
709 744 }
745 // generic text
746 else if (searchType === 'text') {
747 icon = '';
748 }
710 749
711 750 var tmpl = '<div class="ac-container-wrap">{0}{1}</div>';
712 751 return tmpl.format(icon, valueDisplay);
@@ -716,25 +755,52 b''
716 755 if (suggestion.type === "hint") {
717 756 // we skip action
718 757 $('#main_filter').focus();
758 }
759 else if (suggestion.type === "text") {
760 // we skip action
761 $('#main_filter').focus();
762
719 763 } else {
720 764 window.location = suggestion['url'];
721 765 }
722 766 };
767
723 768 var autocompleteMainFilterResult = function (suggestion, originalQuery, queryLowerCase) {
724 769 if (queryLowerCase.split(':').length === 2) {
725 770 queryLowerCase = queryLowerCase.split(':')[1]
726 771 }
772 if (suggestion.type === "text") {
773 // special case we don't want to "skip" display for
774 return true
775 }
727 776 return suggestion.value_display.toLowerCase().indexOf(queryLowerCase) !== -1;
728 777 };
729 778
779 var cleanContext = {
780 repo_view_type: null,
781
782 repo_id: null,
783 repo_name: "",
784
785 repo_group_id: null,
786 repo_group_name: null
787 };
788 var removeGoToFilter = function () {
789 $('.searchTagHidable').hide();
790 $('#main_filter').autocomplete(
791 'setOptions', {params:{search_context: cleanContext}});
792 };
793
730 794 $('#main_filter').autocomplete({
731 795 serviceUrl: pyroutes.url('goto_switcher_data'),
732 params: {"search_context": templateContext.search_context},
796 params: {
797 "search_context": templateContext.search_context
798 },
733 799 minChars:2,
734 800 maxHeight:400,
735 801 deferRequestBy: 300, //miliseconds
736 802 tabDisabled: true,
737 autoSelectFirst: true,
803 autoSelectFirst: false,
738 804 formatResult: autocompleteMainFilterFormatResult,
739 805 lookupFilter: autocompleteMainFilterResult,
740 806 onSelect: function (element, suggestion) {
@@ -753,6 +819,18 b''
753 819 $('#main_filter_help').toggle();
754 820 };
755 821
822 $('#main_filter').on('keydown.autocomplete', function (e) {
823
824 var BACKSPACE = 8;
825 var el = $(e.currentTarget);
826 if(e.which === BACKSPACE){
827 var inputVal = el.val();
828 if (inputVal === ""){
829 removeGoToFilter()
830 }
831 }
832 });
833
756 834 </script>
757 835 <script src="${h.asset('js/rhodecode/base/keyboard-bindings.js', ver=c.rhodecode_version_hash)}"></script>
758 836 </%def>
@@ -7,7 +7,7 b" go_import_header = ''"
7 7 if hasattr(c, 'rhodecode_db_repo'):
8 8 c.template_context['repo_type'] = c.rhodecode_db_repo.repo_type
9 9 c.template_context['repo_landing_commit'] = c.rhodecode_db_repo.landing_rev[1]
10 ## check repo context
10 c.template_context['repo_id'] = c.rhodecode_db_repo.repo_id
11 11 c.template_context['repo_view_type'] = h.get_repo_view_type(request)
12 12
13 13 if getattr(c, 'repo_group', None):
@@ -29,6 +29,7 b" c.template_context['default_user'] = {"
29 29 c.template_context['search_context'] = {
30 30 'repo_group_id': c.template_context.get('repo_group_id'),
31 31 'repo_group_name': c.template_context.get('repo_group_name'),
32 'repo_id': c.template_context.get('repo_id'),
32 33 'repo_name': c.template_context.get('repo_name'),
33 34 'repo_view_type': c.template_context.get('repo_view_type'),
34 35 }
@@ -37,9 +37,9 b''
37 37
38 38 <%def name="menu_bar_subnav()">
39 39 %if c.repo_name:
40 ${self.repo_menu(active='search')}
40 ${self.repo_menu(active='summary')}
41 41 %elif c.repo_group_name:
42 ${self.repo_group_menu(active='search')}
42 ${self.repo_group_menu(active='home')}
43 43 %endif
44 44 </%def>
45 45
General Comments 0
You need to be logged in to leave comments. Login now