Implement full text search (client side) Fixes #1699
This commit is contained in:
parent
23ad11d232
commit
2a9e0b4b81
@ -94,6 +94,14 @@ angular.module('OpenSlidesApp.assignments', [])
|
||||
},
|
||||
getAgendaTitle: function () {
|
||||
return this.title;
|
||||
},
|
||||
// link name which is shown in search result
|
||||
getSearchResultName: function () {
|
||||
return this.getAgendaTitle();
|
||||
},
|
||||
// subtitle of search result
|
||||
getSearchResultSubtitle: function () {
|
||||
return "Election";
|
||||
}
|
||||
},
|
||||
relations: {
|
||||
|
@ -199,25 +199,15 @@ img {
|
||||
#nav .searchbar {
|
||||
float: right;
|
||||
margin-top: 35px;
|
||||
display: inline-table;
|
||||
}
|
||||
|
||||
.searchbar .input-medium {
|
||||
float: left;
|
||||
height: 28px;
|
||||
width: 200px;
|
||||
border: 1px solid #ccc;
|
||||
padding: 0 5px;
|
||||
font-size: 14px;
|
||||
#nav .searchbar input {
|
||||
width: 150px;
|
||||
}
|
||||
|
||||
.searchbar .btn {
|
||||
float: left;
|
||||
height: 30px;
|
||||
width: 30px;
|
||||
#nav .searchbar .btn {
|
||||
background: #e8eaed;
|
||||
border: 1px solid #ccc;
|
||||
border-left: none;
|
||||
font-size: 14px;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
@ -617,6 +607,13 @@ img {
|
||||
content: ":";
|
||||
}
|
||||
|
||||
/* search results */
|
||||
.searchresults li {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.searchresults li .subtitle {
|
||||
color: #999999;
|
||||
}
|
||||
|
||||
/* ngDialog: override ngdialog-theme-default */
|
||||
|
||||
@ -796,12 +793,19 @@ tr.selected td {
|
||||
|
||||
|
||||
|
||||
/* display for resolutions smaller that 880px */
|
||||
@media only screen and (max-width: 880px) {
|
||||
/* display for resolutions smaller that 900px */
|
||||
@media only screen and (max-width: 900px) {
|
||||
|
||||
#nav .navbar li a { padding: 24px 5px; }
|
||||
}
|
||||
|
||||
/* display for resolutions smaller that 760px */
|
||||
@media only screen and (max-width: 760px) {
|
||||
|
||||
#nav .navbar li a { padding: 24px 2px; }
|
||||
#nav .searchbar input { width: 100px; }
|
||||
}
|
||||
|
||||
|
||||
/* display for resolutions smaller that 480px */
|
||||
@media only screen and (max-width: 480px) {
|
||||
@ -821,7 +825,7 @@ tr.selected td {
|
||||
#nav .navbar .button { display: block;}
|
||||
#nav .navbar .button i { padding-top: 15px;}
|
||||
#nav .searchbar { margin-top: 15px; }
|
||||
.searchbar .input-medium { width: 150px; }
|
||||
#nav .searchbar input { width: 150px; }
|
||||
|
||||
#chatbox { width: 100%; top: 130px; }
|
||||
.optional { /* hide optional column */
|
||||
|
@ -251,7 +251,15 @@ angular.module('OpenSlidesApp.core', [
|
||||
},
|
||||
getAgendaTitle: function () {
|
||||
return this.title;
|
||||
}
|
||||
},
|
||||
// link name which is shown in search result
|
||||
getSearchResultName: function () {
|
||||
return this.getAgendaTitle();
|
||||
},
|
||||
// subtitle of search result
|
||||
getSearchResultSubtitle: function () {
|
||||
return "Agenda item";
|
||||
},
|
||||
},
|
||||
relations: {
|
||||
belongsTo: {
|
||||
|
@ -209,11 +209,13 @@ angular.module('OpenSlidesApp.core.site', [
|
||||
abstract: true,
|
||||
template: "<ui-view/>",
|
||||
})
|
||||
|
||||
// legal notice and version
|
||||
.state('legalnotice', {
|
||||
url: '/legalnotice',
|
||||
controller: 'LegalNoticeCtrl',
|
||||
})
|
||||
|
||||
//config
|
||||
.state('config', {
|
||||
url: '/config',
|
||||
@ -224,6 +226,14 @@ angular.module('OpenSlidesApp.core.site', [
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// search
|
||||
.state('search', {
|
||||
url: '/search?q',
|
||||
controller: 'SearchCtrl',
|
||||
templateUrl: 'static/templates/search.html',
|
||||
})
|
||||
|
||||
// customslide
|
||||
.state('core.customslide', {
|
||||
url: '/customslide',
|
||||
@ -449,6 +459,47 @@ angular.module('OpenSlidesApp.core.site', [
|
||||
}
|
||||
])
|
||||
|
||||
// Search Bar Controller
|
||||
.controller('SearchBarCtrl', [
|
||||
'$scope',
|
||||
'$state',
|
||||
function ($scope, $state) {
|
||||
$scope.search = function(query) {
|
||||
$scope.query = '';
|
||||
$state.go('search', {q: query});
|
||||
}
|
||||
}
|
||||
])
|
||||
// Search Controller
|
||||
.controller('SearchCtrl', [
|
||||
'$scope',
|
||||
'$http',
|
||||
'$stateParams',
|
||||
'DS',
|
||||
function ($scope, $http, $stateParams, DS) {
|
||||
// search function
|
||||
$scope.search = function(query) {
|
||||
$http.get('/core/search_api/?q=' + query).then(function(success) {
|
||||
var elements = success.data.elements;
|
||||
$scope.results = [];
|
||||
angular.forEach(elements, function(element) {
|
||||
DS.find(element.collection, element.id).then(function(data) {
|
||||
data.urlState = element.collection.replace('/','.')+'.detail';
|
||||
data.urlParam = {id: element.id};
|
||||
$scope.results.push(data);
|
||||
});
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
// run search with get parameter from url
|
||||
if ($stateParams.q) {
|
||||
$scope.search($stateParams.q);
|
||||
$scope.query = $stateParams.q;
|
||||
}
|
||||
}
|
||||
])
|
||||
|
||||
|
||||
// Provide generic customslide form fields for create and update view
|
||||
.factory('CustomslideForm', [
|
||||
|
@ -135,6 +135,19 @@
|
||||
</a>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="searchbar pull-right" ng-controller="SearchBarCtrl">
|
||||
<form ng-submit="search(query)">
|
||||
<div class="input-group">
|
||||
<input ng-model="query" class="form-control" type="text" placeholder="{{ 'Search' | translate}}">
|
||||
<span class="input-group-btn">
|
||||
<button type="submit" class="btn btn-default">
|
||||
<i class="fa fa-search"></i>
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div><!--end nav-->
|
||||
|
||||
|
@ -15,6 +15,10 @@ urlpatterns = [
|
||||
views.VersionView.as_view(),
|
||||
name='core_version'),
|
||||
|
||||
url(r'^core/search_api/$',
|
||||
views.SearchView.as_view(),
|
||||
name='core_search'),
|
||||
|
||||
url(r'^angular_js/(?P<openslides_app>site|projector)/$',
|
||||
views.AppsJsView.as_view(),
|
||||
name='core_apps_js'),
|
||||
@ -22,9 +26,6 @@ urlpatterns = [
|
||||
# View for the projectors are handelt by angular.
|
||||
url(r'^projector.*$', views.ProjectorView.as_view()),
|
||||
|
||||
url(r'^search/$',
|
||||
views.SearchView.as_view(),
|
||||
name='core_search'),
|
||||
|
||||
# Main entry point for all angular pages.
|
||||
# Has to be the last entry in the urls.py
|
||||
|
@ -202,6 +202,14 @@ angular.module('OpenSlidesApp.motions', ['OpenSlidesApp.users'])
|
||||
}
|
||||
return "Motion " + value + ': ' + this.getTitle();
|
||||
},
|
||||
// link name which is shown in search result
|
||||
getSearchResultName: function () {
|
||||
return this.getAgendaTitle();
|
||||
},
|
||||
// subtitle of search result
|
||||
getSearchResultSubtitle: function () {
|
||||
return "Motion";
|
||||
},
|
||||
isAllowed: function (action) {
|
||||
/*
|
||||
* Return true if the requested user is allowed to do the specific action.
|
||||
|
@ -134,6 +134,14 @@ angular.module('OpenSlidesApp.users', [])
|
||||
});
|
||||
return _.uniq(allPerms);
|
||||
},
|
||||
// link name which is shown in search result
|
||||
getSearchResultName: function () {
|
||||
return this.get_full_name();
|
||||
},
|
||||
// subtitle of search result
|
||||
getSearchResultSubtitle: function () {
|
||||
return "Participant";
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user