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