TopQuickSearch für den Benutzer konfigurierbar gemacht.
[kivitendo-erp.git] / SL / Controller / TopQuickSearch.pm
1 package SL::Controller::TopQuickSearch;
2
3 use strict;
4 use parent qw(SL::Controller::Base);
5
6 use SL::ClientJS;
7 use SL::JSON;
8 use SL::Locale::String qw(t8);
9 use SL::Helper::UserPreferences;
10
11 use Rose::Object::MakeMethods::Generic (
12  'scalar --get_set_init' => [ qw(module js) ],
13 );
14
15 my @available_modules = (
16   'SL::Controller::TopQuickSearch::Article',
17   'SL::Controller::TopQuickSearch::Part',
18   'SL::Controller::TopQuickSearch::Service',
19   'SL::Controller::TopQuickSearch::Assembly',
20   'SL::Controller::TopQuickSearch::Assortment',
21   'SL::Controller::TopQuickSearch::Contact',
22   'SL::Controller::TopQuickSearch::SalesQuotation',
23   'SL::Controller::TopQuickSearch::SalesOrder',
24   'SL::Controller::TopQuickSearch::RequestForQuotation',
25   'SL::Controller::TopQuickSearch::PurchaseOrder',
26   'SL::Controller::TopQuickSearch::GLTransaction',
27   'SL::Controller::TopQuickSearch::Customer',
28   'SL::Controller::TopQuickSearch::Vendor',
29 );
30 my %modules_by_name;
31
32 sub action_query_autocomplete {
33   my ($self) = @_;
34
35   my $hashes = $self->module->query_autocomplete;
36
37   $self->render(\ SL::JSON::to_json($hashes), { layout => 0, type => 'json', process => 0 });
38 }
39
40 sub action_select_autocomplete {
41   my ($self) = @_;
42
43   my $redirect_url = $self->module->select_autocomplete;
44
45   $self->js->redirect_to($redirect_url)->render;
46 }
47
48 sub action_do_search {
49   my ($self) = @_;
50
51   my $redirect_url = $self->module->do_search;
52
53   if ($redirect_url) {
54     $self->js->redirect_to($redirect_url)
55   }
56
57   $self->js->render;
58 }
59
60 sub available_modules {
61   my ($self) = @_;
62
63   $self->require_modules;
64
65   map { $_->new } @available_modules;
66 }
67
68 sub enabled_modules {
69   my $user_prefs = SL::Helper::UserPreferences->new(
70     namespace         => 'TopQuickSearch',
71   );
72
73   my %enabled_names;
74   if ($user_prefs) {
75     my $prefs_val            = $user_prefs->get('quick_search_modules');
76     my @quick_search_modules = split ',', $prefs_val;
77
78     %enabled_names = map {
79       $_ => 1
80     } @quick_search_modules ;
81   } else {
82     %enabled_names = map {
83       $_ => 1
84     } @{ $::instance_conf->get_quick_search_modules };
85   }
86
87   grep {
88     $enabled_names{$_->name}
89   } $_[0]->available_modules
90 }
91
92 sub active_modules {
93   grep {
94     $::auth->assert($_->auth, 1)
95   } $_[0]->enabled_modules
96 }
97
98 sub init_module {
99   my ($self) = @_;
100
101   $self->require_modules;
102
103   die 'Need module' unless $::form->{module};
104
105   die 'Unknown module ' . $::form->{module} unless my $class = $modules_by_name{$::form->{module}};
106
107   $::auth->assert($class->auth);
108
109   return $class->new;
110 }
111
112 sub init_js {
113   SL::ClientJS->new(controller => $_[0])
114 }
115
116 sub require_modules {
117   my ($self) = @_;
118
119   if (!$self->{__modules_required}) {
120     for my $class (@available_modules) {
121       eval "require $class" or die $@;
122       $modules_by_name{ $class->name } = $class;
123     }
124     $self->{__modules_required} = 1;
125   }
126 }
127
128 1;
129
130 __END__
131
132 =encoding utf-8
133
134 =head1 NAME
135
136 SL::Controller::TopQuickSearch - Framework for pluggable quicksearch fields in the layout top header.
137
138 =head1 SYNOPSIS
139
140   use SL::Controller::TopQuickSearch;
141   my $search = SL::Controller::TopQuickSearch->new;
142   $::request->layout->add_javascripts('kivi.QuickSearch.js');
143
144   # in template
145   [%- FOREACH module = search.enabled_modules %]
146   <input type='text' id='top-search-[% module.name %]'>
147   [%- END %]
148
149 =head1 DESCRIPTION
150
151 This controller provides abstraction for different search plugins, and ensures
152 that all follow a common useability scheme.
153
154 Modules should be configurable per user, but currently are not. Disabling
155 modules can be done by removing them from available_modules or in client_config.
156
157 =head1 BEHAVIOUR REQUIREMENTS
158
159 =over 4
160
161 =item *
162
163 A single text input field with the html5 placeholder containing a small
164 description of the target will be rendered from the plugin information.
165
166 =item *
167
168 On typing, the autocompletion must be enabled.
169
170 =item *
171
172 On C<Enter>, the search should redirect to an appropriate listing of matching
173 results.
174
175 If only one item matches the result, the plugin should instead redirect
176 directly to the matched item.
177
178 =item *
179
180 Search terms should accept the broadest possible matching, and if possible with
181 C<multi> parsing.
182
183 =item *
184
185 In case nothing is found, a visual indicator should be given, but no actual
186 redirect should occur.
187
188 =item *
189
190 Each search must check rights and must not present a backdoor into data that
191 the user should not see.
192
193 =item *
194
195 By design the search must not try to guess C<exact matches>.
196
197 =back
198
199 =head1 INTERFACE
200
201 The full interface is described in L<SL::Controller::TopQuickSeach::Base>
202
203 =head1 TODO
204
205   * user configuration
206
207 =head1 BUGS
208
209 None yet :)
210
211 =head1 AUTHOR
212
213 Sven Schöling E<lt>s.schoeling@linet-services.deE<gt>
214
215 =cut