TopQuickSearch: UserPreferences kleinere Syntaxverbesserungen
[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 @quick_search_modules;
74   if (my $prefs_val = $user_prefs->get('quick_search_modules')) {
75     @quick_search_modules = split ',', $prefs_val;
76   } else {
77     @quick_search_modules = @{ $::instance_conf->get_quick_search_modules };
78   }
79
80   my %enabled_names = map { $_ => 1 } @quick_search_modules;
81
82   grep {
83     $enabled_names{$_->name}
84   } $_[0]->available_modules
85 }
86
87 sub active_modules {
88   grep {
89     $::auth->assert($_->auth, 1)
90   } $_[0]->enabled_modules
91 }
92
93 sub init_module {
94   my ($self) = @_;
95
96   $self->require_modules;
97
98   die 'Need module' unless $::form->{module};
99
100   die 'Unknown module ' . $::form->{module} unless my $class = $modules_by_name{$::form->{module}};
101
102   $::auth->assert($class->auth);
103
104   return $class->new;
105 }
106
107 sub init_js {
108   SL::ClientJS->new(controller => $_[0])
109 }
110
111 sub require_modules {
112   my ($self) = @_;
113
114   if (!$self->{__modules_required}) {
115     for my $class (@available_modules) {
116       eval "require $class" or die $@;
117       $modules_by_name{ $class->name } = $class;
118     }
119     $self->{__modules_required} = 1;
120   }
121 }
122
123 1;
124
125 __END__
126
127 =encoding utf-8
128
129 =head1 NAME
130
131 SL::Controller::TopQuickSearch - Framework for pluggable quicksearch fields in the layout top header.
132
133 =head1 SYNOPSIS
134
135   use SL::Controller::TopQuickSearch;
136   my $search = SL::Controller::TopQuickSearch->new;
137   $::request->layout->add_javascripts('kivi.QuickSearch.js');
138
139   # in template
140   [%- FOREACH module = search.enabled_modules %]
141   <input type='text' id='top-search-[% module.name %]'>
142   [%- END %]
143
144 =head1 DESCRIPTION
145
146 This controller provides abstraction for different search plugins, and ensures
147 that all follow a common useability scheme.
148
149 Modules should be configurable per user, but currently are not. Disabling
150 modules can be done by removing them from available_modules or in client_config.
151
152 =head1 BEHAVIOUR REQUIREMENTS
153
154 =over 4
155
156 =item *
157
158 A single text input field with the html5 placeholder containing a small
159 description of the target will be rendered from the plugin information.
160
161 =item *
162
163 On typing, the autocompletion must be enabled.
164
165 =item *
166
167 On C<Enter>, the search should redirect to an appropriate listing of matching
168 results.
169
170 If only one item matches the result, the plugin should instead redirect
171 directly to the matched item.
172
173 =item *
174
175 Search terms should accept the broadest possible matching, and if possible with
176 C<multi> parsing.
177
178 =item *
179
180 In case nothing is found, a visual indicator should be given, but no actual
181 redirect should occur.
182
183 =item *
184
185 Each search must check rights and must not present a backdoor into data that
186 the user should not see.
187
188 =item *
189
190 By design the search must not try to guess C<exact matches>.
191
192 =back
193
194 =head1 INTERFACE
195
196 The full interface is described in L<SL::Controller::TopQuickSeach::Base>
197
198 =head1 TODO
199
200   * user configuration
201
202 =head1 BUGS
203
204 None yet :)
205
206 =head1 AUTHOR
207
208 Sven Schöling E<lt>s.schoeling@linet-services.deE<gt>
209
210 =cut